Other Source Code stuff
|   | To do Kill this entire section, it was made when 2.0 was the latest release. Besides which, Source Code Documentation is meant to replace it anyway
 | 
x<<y = x * 2^y (Left shifting)
x>>y = x / 2^y (Right shifting)
x++ = x + 1
x-- = x - 1
m_fixed.h
fixed_t:
- Min = -2147483648 (-1 * 2^31, or -32768*FRACUNIT)
- Max = 2147483647 (2^31 - 1, or 32767*FRACUNIT- 1)
doomdata.h
Map level types
"BSP" = Binary Space Partition
- ML_LABEL(A separator, name, MAPxx)
- ML_THINGS(Things)
- ML_LINEDEFS(Linedefs)
- ML_SIDEDEFS(Sidedefs)
- ML_VERTEXES(Vertices, edited and BSP splits generated)
- ML_SEGS(Linesegs, from linedefs split by BSP)
- ML_SSECTORS(Subsectors, list of linesegs)
- ML_NODES(Nodes)
- ML_SECTORS(Sectors)
- ML_REJECT(LUT, sector-sector visibility)
- ML_BLOCKMAP(LUT, motion clipping, walls/grid element)
info.h
NUMMOBJFREESLOTS = 128
NUMSPRITEFREESLOTS = NUMMOBJFREESLOTS = 128
NUMSTATEFREESLOTS = NUMMOBJFREESLOTS*6 = 768
NUMSPRITES = 445 (Total number of sprites, including freeslots)
NUMSTATES = 2559 (Total number of states, including freeslots)
NUMMOBJTYPES = 445 (Total number of objects, including freeslots)
p_enemy.c
P_CheckMeleeRange
Checks how far the player is from the actor:
- true - the player is within the actor's melee range
- false - the player is too far away
Actions that check P_CheckMeleeRange:
Melee range distance limits:
- if (dist >= MELEERANGE- 20*FRACUNIT+ pl->radius)   return false;- distance >= 64 fracunits - 20 fracunits + player radius
- distance >= 44 fracunits + 16 fracunits
- if distance >= 60 fracunits, P_CheckMeleeRangewill return false
 
- if (dist >= (actor->radius + pl->radius)*2)   return false;
- distance >= (20 fracunits + 16*fracunits)*2
- distance >= (36 fracunits)*2
- if distance >= 72 fracunits, P_CheckMeleeRangewill return false
 
- if (dist >= (actor->radius + pl->radius)*4)   return false;
- dist >= (32 fracunits + 16 fracunits)*4
- dist >= (48 fracunits)*4
- if distance >= 192 fracunits, P_CheckMeleeRangewill return false
 
Melee Range height distance limits
- if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))   return false;
- if the player's z height is higher than the top of the actor, or the actor's z height is higher than the top of the player, P_CheckMeleeRangewill return false
 
- if (pl->z + pl->height > actor->z - (40<<FRACBITS)) return false;
- if the top of the player is higher than 40 fracunits below the actor, P_CheckMeleeRangewill return false
 
- if (pl->z + pl->height > actor->z - (24<<FRACBITS)) return false;
- if the top of the player is higher than 24 fracunits below the actor, P_CheckMeleeRangewill return false
 
| 
|  Code - P_CheckMeleeRange |  
|  |  
| //
// P_CheckMeleeRange
//
static boolean P_CheckMeleeRange(mobj_t *actor)
{
	mobj_t *pl;
	fixed_t dist;
	if (!actor->target)
		return false;
	pl = actor->target;
	dist = P_AproxDistance(pl->x-actor->x, pl->y-actor->y);
	switch (actor->type)
	{
		case MT_JETTBOMBER:
			if (dist >= (actor->radius + pl->radius)*2)
				return false;
			break;
		case MT_FACESTABBER:
			if (dist >= (actor->radius + pl->radius)*4)
				return false;
			break;
		default:
			if (dist >= MELEERANGE - 20*FRACUNIT + pl->radius)
				return false;
			break;
	}
	// check height now, so that damn crawlas cant attack
	// you if you stand on a higher ledge.
	if (actor->type == MT_JETTBOMBER)
	{
		if (pl->z + pl->height > actor->z - (40<<FRACBITS))
			return false;
	}
	else if (actor->type == MT_SKIM)
	{
		if (pl->z + pl->height > actor->z - (24<<FRACBITS))
			return false;
	}
	else
	{
		if ((pl->z > actor->z + actor->height) || (actor->z > pl->z + pl->height))
			return false;
		if (actor->type != MT_JETTBOMBER && actor->type != MT_SKIM
			&& !P_CheckSight(actor, actor->target))
		{
			return false;
		}
	}
	return true;
} |  | 
P_CheckMissileRange
Actions that check P_CheckMissileRange:
| 
|  Code - P_CheckMissileRange |  
|  |  
| //
// P_CheckMissileRange
//
static boolean P_CheckMissileRange(mobj_t *actor)
{
	fixed_t dist;
	if (!P_CheckSight(actor, actor->target))
		return false;
	if (actor->reactiontime)
		return false; // do not attack yet
	// OPTIMIZE: get this from a global checksight
	dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT;
	if (!actor->info->meleestate)
		dist -= 128*FRACUNIT; // no melee attack, so fire more
	dist >>= 16;
	if (actor->type == MT_EGGMOBILE)
		dist >>= 1;
	if (dist > 200)
		dist = 200;
	if (actor->type == MT_EGGMOBILE && dist > 160)
		dist = 160;
	if (P_Random() < dist)
		return false;
	return true;
} |  | 
p_local.h
FLOATSPEED = FRACUNIT*4
- = 4 fracunits
 
MAPBLOCKUNITS = 128
MAPBLOCKSIZE = MAPBLOCKUNITS*FRACUNIT
- = 128*65536
- = 8388608
 
MAPBLOCKSHIFT = FRACBITS+7
- = 16 + 7
- = 23
 
MAPBMASK = MAPBLOCKSIZE-1
- = 8388608 - 1
- = 8388607
 
MAPBTOFRAC = MAPBLOCKSHIFT-FRACBITS
- = 23 - 16
- = 7
 
PLAYERRADIUS = 16*FRACUNIT
- = 16 fracunits
 
MAXRADIUS = 32*FRACUNIT
- = 32 fracunits
 
MAXSTEPMOVE = 24*FRACUNIT
- = 24 fracunits (Maximum height an object, e.g. the player, can walk up/down without jumping)
 
USERANGE = 64*FRACUNIT
- = 64 fracunits
 
MELEERANGE = 64*FRACUNIT
- = 64 fracunits
 
MISSILERANGE = 32*64*FRACUNIT
- = 2048*FRACUNIT
- = 2048 fracunits
 
ONFLOORZ = INT32_MIN
- = -2147483648 (-1 * 2*31, or -32768*FRACUNIT)
 
ONCEILINGZ = INT32_MAX
- = 2147483647 (2*31 - 1, or (32768*FRACUNIT)-1)
 
ITEMQUESIZE = 1024 (Time interval for item respawning)
p_mobj.c/p_mobj.h
STOPSPEED = (FRACUNIT/NEWTICRATERATIO)
- = FRACUNIT
- = 1 fracunit/1 tic (Slowest speed an object can move in any direction - if slower, the object stops moving altogether)
 
FRICTION = (ORIG_FRICTION/NEWTICRATERATIO)
- = ORIG_FRICTION
- = 59392
 
P_GenericBossThinker
(Thinker for custom SOC-made bosses)
| 
|  Code - P_GenericBossThinker |  
|  |  
| // AI for a generic boss.
static void P_GenericBossThinker(mobj_t *mobj)
{
	if (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)
	{
		mobj->flags2 &= ~MF2_FRET;
		mobj->flags &= ~MF_TRANSLATION;
	}
	if (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE))
	{
		if (mobj->health <= 0)
		{
			// look for a new target
			if (P_Look4Players(mobj, true) && mobj->info->mass) // Bid farewell!
				S_StartSound(mobj, mobj->info->mass);
			return;
		}
		// look for a new target
		if (P_Look4Players(mobj, true) && mobj->info->seesound)
			S_StartSound(mobj, mobj->info->seesound);
		return;
	}
	if (mobj->state == &states[mobj->info->spawnstate])
		A_Boss1Chase(mobj);
	if (mobj->state == &states[mobj->info->meleestate]
		|| (mobj->state == &states[mobj->info->missilestate]
		&& mobj->health > mobj->info->damage))
	{
		mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
	}
} |  | 
P_Boss1Thinker
(Thinker for the Egg Mobile)
| 
|  Code - P_Boss1Thinker |  
|  |  
| // AI for the first boss.
static void P_Boss1Thinker(mobj_t *mobj)
{
	if (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)
	{
		mobj->flags2 &= ~MF2_FRET;
		mobj->flags &= ~MF_TRANSLATION;
	}
	if (!mobj->tracer)
	{
		var1 = 0;
		A_BossJetFume(mobj);
	}
	if (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE))
	{
		if (mobj->health <= 0)
		{
			if (P_Look4Players(mobj, true) && mobj->info->mass) // Bid farewell!
				S_StartSound(mobj, mobj->info->mass);
			return;
		}
		// look for a new target
		if (P_Look4Players(mobj, true) && mobj->info->seesound)
			S_StartSound(mobj, mobj->info->seesound);
		return;
	}
	if (mobj->state == &states[mobj->info->spawnstate])
		A_Boss1Chase(mobj);
	if (mobj->state == &states[mobj->info->meleestate]
		|| (mobj->state == &states[mobj->info->missilestate]
		&& mobj->health > mobj->info->damage))
	{
		mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
	}
} |  | 
P_Boss2Thinker
(Thinker for the Egg Slimer)
| 
|  Code - P_Boss2Thinker |  
|  |  
| // AI for the second boss.
// No, it does NOT convert "Boss" to a "Thinker". =P
static void P_Boss2Thinker(mobj_t *mobj)
{
	if (mobj->movecount)
		mobj->movecount--;
	if (!(mobj->movecount))
	{
		mobj->flags2 &= ~MF2_FRET;
		mobj->flags &= ~MF_TRANSLATION;
	}
	if (!mobj->tracer
#ifdef CHAOSISNOTDEADYET
		&& gametype != GT_CHAOS
#endif
		)
	{
		var1 = 0;
		A_BossJetFume(mobj);
	}
	if (mobj->health <= mobj->info->damage && (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE)))
	{
		if (mobj->health <= 0)
		{
			// look for a new target
			if (P_Look4Players(mobj, true) && mobj->info->mass) // Bid farewell!
				S_StartSound(mobj, mobj->info->mass);
			return;
		}
		// look for a new target
		if (P_Look4Players(mobj, true) && mobj->info->seesound)
			S_StartSound(mobj, mobj->info->seesound);
		return;
	}
#ifdef CHAOSISNOTDEADYET
	if (gametype == GT_CHAOS && (mobj->state == &states[S_EGGMOBILE2_POGO1]
		|| mobj->state == &states[S_EGGMOBILE2_POGO2]
		|| mobj->state == &states[S_EGGMOBILE2_POGO3]
		|| mobj->state == &states[S_EGGMOBILE2_POGO4]
		|| mobj->state == &states[S_EGGMOBILE2_STND])) // Chaos mode, he pogos only
	{
		mobj->flags &= ~MF_NOGRAVITY;
		A_Boss2Pogo(mobj);
	}
	else if (gametype != GT_CHAOS)
#endif
	{
		if (mobj->state == &states[mobj->info->spawnstate] && mobj->health > mobj->info->damage)
			A_Boss2Chase(mobj);
		else if (mobj->state == &states[mobj->info->raisestate]
			|| mobj->state == &states[S_EGGMOBILE2_POGO2]
			|| mobj->state == &states[S_EGGMOBILE2_POGO3]
			|| mobj->state == &states[S_EGGMOBILE2_POGO4]
			|| mobj->state == &states[mobj->info->spawnstate])
		{
			mobj->flags &= ~MF_NOGRAVITY;
			A_Boss2Pogo(mobj);
		}
	}
} |  | 
P_Boss3Thinker
(Thinker for the Sea Egg)
| 
|  Code - P_Boss3Thinker |  
|  |  
| // AI for the third boss.
static void P_Boss3Thinker(mobj_t *mobj)
{
	if (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)
	{
		mobj->flags2 &= ~MF2_FRET;
		mobj->flags &= ~MF_TRANSLATION;
	}
	if (mobj->flags2 & MF2_FRET)
	{
		mobj->movedir = 1;
		if (mobj->health <= mobj->info->damage)
		{
			var1 = 100;
			var2 = 0;
			A_LinedefExecute(mobj);
		}
	}
	if (mobj->movefactor > ORIG_FRICTION_FACTOR)
	{
		mobj->movefactor--;
		return;
	}
	if (!mobj->tracer)
	{
		var1 = 1;
		A_BossJetFume(mobj);
	}
	if (mobj->health <= 0)
	{
		mobj->movecount = 0;
		mobj->reactiontime = 0;
		if (mobj->state < &states[mobj->info->xdeathstate])
			return;
		if (mobj->threshold == -1)
		{
			mobj->momz = mobj->info->speed;
			return;
		}
	}
	if (mobj->reactiontime && mobj->health > mobj->info->damage) // Shock mode
	{
		UINT32 i;
		if (mobj->state != &states[mobj->info->spawnstate])
			P_SetMobjState(mobj, mobj->info->spawnstate);
		if (leveltime % 2*TICRATE == 0)
		{
			ffloor_t *rover;
			// Shock the water
			for (i = 0; i < MAXPLAYERS; i++)
			{
				if (!playeringame[i])
					continue;
				if (!players[i].mo)
					continue;
				if (players[i].mo->health <= 0)
					continue;
				if (players[i].mo->eflags & MFE_UNDERWATER)
					P_DamageMobj(players[i].mo, mobj, mobj, 1);
			}
			// Make the water flash
			for (i = 0; i < numsectors; i++)
			{
				if (!sectors[i].ffloors)
					continue;
				for (rover = sectors[i].ffloors; rover; rover = rover->next)
				{
					if (!(rover->flags & FF_EXISTS))
						continue;
					if (!(rover->flags & FF_SWIMMABLE))
						continue;
					P_SpawnLightningFlash(rover->master->frontsector);
					break;
				}
			}
			if (leveltime % 35 == 0)
				S_StartSound(0, sfx_buzz1);
		}
		// If in the center, check to make sure
		// none of the players are in the water
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (players[i].mo->eflags & MFE_UNDERWATER)
				return; // Stay put
		}
		mobj->reactiontime = 0;
	}
	else if (mobj->movecount) // Firing mode
	{
		UINT32 i;
		// look for a new target
		P_Look4Players(mobj, true);
		if (!mobj->target || !mobj->target->player)
			return;
		// Are there any players underwater? If so, shock them!
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (players[i].mo->eflags & MFE_UNDERWATER)
			{
				mobj->movecount = 0;
				P_SetMobjState(mobj, mobj->info->spawnstate);
				break;
			}
		}
		// Always face your target.
		A_FaceTarget(mobj);
		// Check if the attack animation is running. If not, play it.
		if (mobj->state < &states[mobj->info->missilestate] || mobj->state > &states[mobj->info->raisestate])
			P_SetMobjState(mobj, mobj->info->missilestate);
	}
	else if (mobj->threshold >= 0) // Traveling mode
	{
		thinker_t *th;
		mobj_t *mo2;
		fixed_t dist, dist2;
		fixed_t speed;
		P_SetTarget(&mobj->target, NULL);
		if (mobj->state != &states[mobj->info->spawnstate] && mobj->health > 0
			&& !(mobj->flags2 & MF2_FRET))
			P_SetMobjState(mobj, mobj->info->spawnstate);
		// scan the thinkers
		// to find a point that matches
		// the number
		for (th = thinkercap.next; th != &thinkercap; th = th->next)
		{
			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
				continue;
			mo2 = (mobj_t *)th;
			if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == mobj->threshold)
			{
				P_SetTarget(&mobj->target, mo2);
				break;
			}
		}
		if (!mobj->target) // Should NEVER happen
		{
			CONS_Printf("Error: Boss 3 was unable to find specified waypoint: %d\n", mobj->threshold);
			return;
		}
		dist = P_AproxDistance(P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y), mobj->target->z - mobj->z);
		if (dist < 1)
			dist = 1;
		if ((mobj->movedir) || (mobj->health <= mobj->info->damage))
			speed = mobj->info->speed * 2;
		else
			speed = mobj->info->speed;
		mobj->momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed);
		mobj->momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed);
		mobj->momz = FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed);
		mobj->angle = R_PointToAngle(mobj->momx, mobj->momy);
		dist2 = P_AproxDistance(P_AproxDistance(mobj->target->x - (mobj->x + mobj->momx), mobj->target->y - (mobj->y + mobj->momy)), mobj->target->z - (mobj->z + mobj->momz));
		if (dist2 < 1)
			dist2 = 1;
		if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
		{
			// If further away, set XYZ of mobj to waypoint location
			P_UnsetThingPosition(mobj);
			mobj->x = mobj->target->x;
			mobj->y = mobj->target->y;
			mobj->z = mobj->target->z;
			mobj->momx = mobj->momy = mobj->momz = 0;
			P_SetThingPosition(mobj);
			if (mobj->threshold == 0)
			{
				mobj->reactiontime = 1; // Bzzt! Shock the water!
				mobj->movedir = 0;
				if (mobj->health <= 0)
				{
					mobj->flags |= MF_NOGRAVITY|MF_NOCLIP;
					mobj->flags |= MF_NOCLIPHEIGHT;
					mobj->threshold = -1;
					return;
				}
			}
			// Set to next waypoint in sequence
			if (mobj->target->spawnpoint)
			{
				// From the center point, choose one of the five paths
				if (mobj->target->spawnpoint->angle == 0)
					mobj->threshold = (P_Random()%5) + 1;
				else
					mobj->threshold = mobj->target->spawnpoint->extrainfo;
				// If the deaf flag is set, go into firing mode
				if (mobj->target->spawnpoint->options & MTF_AMBUSH)
				{
					if (mobj->health <= mobj->info->damage)
						mobj->movefactor = ORIG_FRICTION_FACTOR + 5*TICRATE;
					else
						mobj->movecount = 1;
				}
			}
			else // This should never happen, as well
				CONS_Printf("Error: Boss 3 waypoint has no spawnpoint associated with it.\n");
		}
	}
} |  | 
P_Boss7Thinker
(Thinker for Brak Eggman)
| 
|  Code - P_Boss7Thinker |  
|  |  
| // AI for Black Eggman
//
// Sorry for all of the code copypaste from p_enemy.c
// Maybe someone can un-static a lot of this stuff so it
// can be called from here?
//
// Note: You CANNOT have more than ONE Black Eggman
// in a level! Just don't try it!
//
//
typedef enum
{
	DI_NODIR = -1,
	DI_EAST = 0,
	DI_NORTHEAST = 1,
	DI_NORTH = 2,
	DI_NORTHWEST = 3,
	DI_WEST = 4,
	DI_SOUTHWEST = 5,
	DI_SOUTH = 6,
	DI_SOUTHEAST = 7,
	NUMDIRS = 8,
} dirtype_t;
//
// P_NewChaseDir related LUT.
//
static dirtype_t opposite[] =
{
	DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
	DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
};
static dirtype_t diags[] =
{
	DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
};
static const fixed_t xspeed[NUMDIRS] = {FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000, 0, 47000};
static const fixed_t yspeed[NUMDIRS] = {0, 47000, FRACUNIT, 47000, 0, -47000, -FRACUNIT, -47000};
/** Moves an actor in its current direction.
  *
  * \param actor Actor object to move.
  * \return False if the move is blocked, otherwise true.
  */
static boolean P_Move(mobj_t *actor, fixed_t speed)
{
	fixed_t tryx, tryy;
	dirtype_t movedir = actor->movedir;
	if (movedir == DI_NODIR || !actor->health)
		return false;
	I_Assert((unsigned)movedir < 8);
	tryx = actor->x + speed*xspeed[movedir];
	tryy = actor->y + speed*yspeed[movedir];
	if (!P_TryMove(actor, tryx, tryy, false))
	{
		if (actor->flags & MF_FLOAT && floatok)
		{
			// must adjust height
			if (actor->z < tmfloorz)
				actor->z += FLOATSPEED;
			else
				actor->z -= FLOATSPEED;
			actor->flags2 |= MF2_INFLOAT;
			return true;
		}
		return false;
	}
	else
		actor->flags2 &= ~MF2_INFLOAT;
	return true;
}
/** Attempts to move an actor on in its current direction.
  * If the move succeeds, the actor's move count is reset
  * randomly to a value from 0 to 15.
  *
  * \param actor Actor to move.
  * \return True if the move succeeds, false if the move is blocked.
  */
static boolean P_TryWalk(mobj_t *actor)
{
	if (!P_Move(actor, actor->info->speed))
		return false;
	actor->movecount = P_Random() & 15;
	return true;
}
static void P_NewChaseDir(mobj_t *actor)
{
	fixed_t deltax, deltay;
	dirtype_t d[3];
	dirtype_t tdir = DI_NODIR, olddir, turnaround;
#ifdef PARANOIA
	if (!actor->target)
		I_Error("P_NewChaseDir: called with no target");
#endif
	olddir = actor->movedir;
	if (olddir >= NUMDIRS)
		olddir = DI_NODIR;
	if (olddir != DI_NODIR)
		turnaround = opposite[olddir];
	else
		turnaround = olddir;
	deltax = actor->target->x - actor->x;
	deltay = actor->target->y - actor->y;
	if (deltax > 10*FRACUNIT)
		d[1] = DI_EAST;
	else if (deltax < -10*FRACUNIT)
		d[1] = DI_WEST;
	else
		d[1] = DI_NODIR;
	if (deltay < -10*FRACUNIT)
		d[2] = DI_SOUTH;
	else if (deltay > 10*FRACUNIT)
		d[2] = DI_NORTH;
	else
		d[2] = DI_NODIR;
	// try direct route
	if (d[1] != DI_NODIR && d[2] != DI_NODIR)
	{
		dirtype_t newdir = diags[((deltay < 0)<<1) + (deltax > 0)];
		actor->movedir = newdir;
		if ((newdir != turnaround) && P_TryWalk(actor))
			return;
	}
	// try other directions
	if (P_Random() > 200 || abs(deltay) > abs(deltax))
	{
		tdir = d[1];
		d[1] = d[2];
		d[2] = tdir;
	}
	if (d[1] == turnaround)
		d[1] = DI_NODIR;
	if (d[2] == turnaround)
		d[2] = DI_NODIR;
	if (d[1] != DI_NODIR)
	{
		actor->movedir = d[1];
		if (P_TryWalk(actor))
			return; // either moved forward or attacked
	}
	if (d[2] != DI_NODIR)
	{
		actor->movedir = d[2];
		if (P_TryWalk(actor))
			return;
	}
	// there is no direct path to the player, so pick another direction.
	if (olddir != DI_NODIR)
	{
		actor->movedir =olddir;
		if (P_TryWalk(actor))
			return;
	}
	// randomly determine direction of search
	if (P_Random() & 1)
	{
		for (tdir = DI_EAST; tdir <= DI_SOUTHEAST; tdir++)
		{
			if (tdir != turnaround)
			{
				actor->movedir = tdir;
				if (P_TryWalk(actor))
					return;
			}
		}
	}
	else
	{
		for (tdir = DI_SOUTHEAST; tdir >= DI_EAST; tdir--)
		{
			if (tdir != turnaround)
			{
				actor->movedir = tdir;
				if (P_TryWalk(actor))
					return;
			}
		}
	}
	if (turnaround != DI_NODIR)
	{
		actor->movedir = turnaround;
		if (P_TryWalk(actor))
			return;
	}
	actor->movedir = (angle_t)DI_NODIR; // cannot move
}
static void P_Boss7Thinker(mobj_t *mobj)
{
	if (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE))
	{
		// look for a new target
		if (P_LookForPlayers(mobj, true, false, 0))
			return; // got a new target
		P_SetMobjStateNF(mobj, mobj->info->spawnstate);
		return;
	}
	if (mobj->health >= 8 && (leveltime & 14) == 0)
		P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height, MT_SMOK)->momz = FRACUNIT;
	if (mobj->state == &states[S_BLACKEGG_STND] && mobj->tics == mobj->state->tics)
	{
		mobj->reactiontime += P_Random();
		if (mobj->health <= 2)
			mobj->reactiontime /= 4;
	}
	else if (mobj->state == &states[S_BLACKEGG_DIE4] && mobj->tics == mobj->state->tics)
	{
		INT32 i;
		thinker_t *th;
		mobj_t *mo2;
		mobj->health = 0;
		// make sure there is a player alive for victory
		for (i = 0; i < MAXPLAYERS; i++)
			if (playeringame[i] && (players[i].health > 0
				|| ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0))))
				break;
		if (i == MAXPLAYERS)
			return; // no one left alive, so do not end game
		// scan the remaining thinkers to see
		// if all bosses are dead
		for (th = thinkercap.next; th != &thinkercap; th = th->next)
		{
			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
				continue;
			mo2 = (mobj_t *)th;
			if (mo2 != mobj && (mo2->flags & MF_BOSS) && mo2->health > 0)
				return; // other boss not dead
		}
		for (i = 0; i < MAXPLAYERS; i++)
				P_DoPlayerExit(&players[i]);
		P_SetTarget(&mobj->target, NULL);
		mobj->flags |= MF_NOCLIP;
		mobj->flags &= ~MF_SPECIAL;
		S_StartSound(0, sfx_befall);
	}
	else if (mobj->state >= &states[S_BLACKEGG_WALK1]
		&& mobj->state <= &states[S_BLACKEGG_WALK6])
	{
		// Chase
		INT32 delta;
		INT32 i;
		if (mobj->z != mobj->floorz)
			return;
		// Self-adjust if stuck on the edge
		if (mobj->tracer)
		{
			if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) > 128*FRACUNIT - mobj->radius)
				P_InstaThrust(mobj, R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y), FRACUNIT);
		}
		if (mobj->flags2 & MF2_FRET)
		{
			P_SetMobjState(mobj, S_BLACKEGG_DESTROYPLAT1);
			S_StartSound(0, sfx_s3k_34);
			mobj->flags2 &= ~MF2_FRET;
			return;
		}
		// turn towards movement direction if not there yet
		if (mobj->movedir < NUMDIRS)
		{
			mobj->angle &= (7<<29);
			delta = mobj->angle - (mobj->movedir << 29);
			if (delta > 0)
				mobj->angle -= ANGLE_45;
			else if (delta < 0)
				mobj->angle += ANGLE_45;
		}
		// Is a player on top of us?
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y) > mobj->radius)
				continue;
			if (players[i].mo->z > mobj->z + mobj->height - 2*FRACUNIT
				&& players[i].mo->z < mobj->z + mobj->height + 32*FRACUNIT)
			{
				// Punch him!
				P_SetMobjState(mobj, mobj->info->meleestate);
				S_StartSound(0, sfx_begrnd); // warning sound
				return;
			}
		}
		if (mobj->health <= 2
			&& mobj->target
			&& mobj->target->player
			&& (mobj->target->player->pflags & PF_ITEMHANG))
		{
			A_FaceTarget(mobj);
			P_SetMobjState(mobj, S_BLACKEGG_SHOOT1);
			mobj->movecount = TICRATE + P_Random()/2;
			return;
		}
		if (mobj->reactiontime)
			mobj->reactiontime--;
		if (mobj->reactiontime <= 0 && mobj->z == mobj->floorz)
		{
			// Here, we'll call P_Random() and decide what kind of attack to do
RetryAttack:
			switch(mobj->threshold)
			{
				case 0: // Lob cannon balls
					if (mobj->z < 1056*FRACUNIT)
					{
						A_FaceTarget(mobj);
						P_SetMobjState(mobj, mobj->info->xdeathstate);
						mobj->movecount = 7*TICRATE + P_Random();
					}
					else
					{
						mobj->threshold++;
						goto RetryAttack;
					}
					break;
				case 1: // Chaingun Goop
					A_FaceTarget(mobj);
					P_SetMobjState(mobj, S_BLACKEGG_SHOOT1);
					if (mobj->health > 2)
						mobj->movecount = TICRATE + P_Random()/3;
					else
						mobj->movecount = TICRATE + P_Random()/2;
					break;
				case 2: // Homing Missile
					A_FaceTarget(mobj);
					P_SetMobjState(mobj, mobj->info->missilestate);
					S_StartSound(0, sfx_beflap);
					break;
			}
			mobj->threshold++;
			mobj->threshold %= 3;
			return;
		}
		// possibly choose another target
		if (multiplayer && (mobj->target->health <= 0 || !P_CheckSight(mobj, mobj->target))
			&& P_LookForPlayers(mobj, true, false, 0))
			return; // got a new target
		if (leveltime & 1)
		{
			// chase towards player
			if (--mobj->movecount < 0 || !P_Move(mobj, mobj->info->speed))
				P_NewChaseDir(mobj);
		}
	}
	else if (mobj->state == &states[S_BLACKEGG_MISSILE3] && mobj->tics == states[S_BLACKEGG_MISSILE3].tics)
	{
		mobj_t dummymo;
		if (!mobj->target)
		{
			P_SetMobjState(mobj, mobj->info->spawnstate);
			return;
		}
		A_FaceTarget(mobj);
		// set dummymo's coordinates
		dummymo.x = mobj->target->x;
		dummymo.y = mobj->target->y;
		dummymo.z = mobj->target->z + 16*FRACUNIT; // raised height
		P_SpawnXYZMissile(mobj, &dummymo, MT_BLACKEGGMAN_MISSILE,
			mobj->x + P_ReturnThrustX(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->y + P_ReturnThrustY(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->z + FixedDiv(mobj->height, 3*FRACUNIT/2));
		P_SpawnXYZMissile(mobj, &dummymo, MT_BLACKEGGMAN_MISSILE,
			mobj->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->z + FixedDiv(mobj->height, 3*FRACUNIT/2));
		P_SpawnXYZMissile(mobj, &dummymo, MT_BLACKEGGMAN_MISSILE,
			mobj->x + P_ReturnThrustX(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->y + P_ReturnThrustY(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->z + mobj->height/2);
		P_SpawnXYZMissile(mobj, &dummymo, MT_BLACKEGGMAN_MISSILE,
			mobj->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->z + mobj->height/2);
	}
	else if (mobj->state == &states[S_BLACKEGG_PAIN1] && mobj->tics == mobj->state->tics)
	{
		if (mobj->health > 0)
			mobj->health--;
		mobj->reactiontime /= 3;
		if (mobj->health <= 0)
		{
			INT32 i;
			P_KillMobj(mobj, NULL, NULL);
			// It was a team effort
			for (i = 0; i < MAXPLAYERS; i++)
			{
				if (playeringame[i])
					continue;
				players[i].score += 1000;
			}
		}
	}
	else if (mobj->state == &states[S_BLACKEGG_PAIN35] && mobj->tics == 1)
	{
		if (mobj->health == 2)
		{
			// Begin platform destruction
			mobj->flags2 |= MF2_FRET;
			P_SetMobjState(mobj, mobj->info->raisestate);
		}
	}
	else if (mobj->state == &states[S_BLACKEGG_HITFACE4] && mobj->tics == mobj->state->tics)
	{
		// This is where Black Eggman hits his face.
		// If a player is on top of him, the player gets hurt.
		// But, if the player has managed to escape,
		// Black Eggman gets hurt!
		INT32 i;
		mobj->state->nextstate = mobj->info->painstate; // Reset
		S_StartSound(0, sfx_bedeen);
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y) > (mobj->radius + players[i].mo->radius))
				continue;
			if (players[i].mo->z > mobj->z + mobj->height - FRACUNIT
				&& players[i].mo->z < mobj->z + mobj->height + 128*FRACUNIT) // You can't be in the vicinity, either...
			{
				// Punch him!
				P_DamageMobj(players[i].mo, mobj, mobj, 1);
				mobj->state->nextstate = mobj->info->spawnstate;
				// Laugh
				S_StartSound(0, sfx_bewar1 + (P_Random() % 4));
			}
		}
	}
	else if (mobj->state == &states[S_BLACKEGG_GOOP])
	{
		// Lob cannon balls
		if (mobj->movecount-- <= 0 || !mobj->target)
		{
			P_SetMobjState(mobj, mobj->info->spawnstate);
			return;
		}
		if ((leveltime & 15) == 0)
		{
			var1 = MT_CANNONBALL;
			var2 = 2*TICRATE + (80<<16);
			A_LobShot(mobj);
			S_StartSound(0, sfx_begoop);
		}
	}
	else if (mobj->state == &states[S_BLACKEGG_SHOOT2])
	{
		// Chaingun goop
		mobj_t *missile;
		if (mobj->movecount-- <= 0 || !mobj->target)
		{
			P_SetMobjState(mobj, mobj->info->spawnstate);
			return;
		}
		A_FaceTarget(mobj);
		missile = P_SpawnXYZMissile(mobj, mobj->target, MT_BLACKEGGMAN_GOOPFIRE,
			mobj->x + P_ReturnThrustX(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->y + P_ReturnThrustY(mobj, mobj->angle-ANGLE_90, FixedDiv(mobj->radius, 3*FRACUNIT/2)+(4*FRACUNIT)),
			mobj->z + FixedDiv(mobj->height, 3*FRACUNIT/2));
		S_StopSound(missile);
		if (leveltime & 1)
			S_StartSound(0, sfx_beshot);
	}
	else if (mobj->state == &states[S_BLACKEGG_JUMP1] && mobj->tics == 1)
	{
		mobj_t *hitspot = NULL, *mo2;
		angle_t an;
		fixed_t dist, closestdist;
		fixed_t vertical, horizontal;
		fixed_t airtime = 5*TICRATE;
		INT32 waypointNum = 0;
		thinker_t *th;
		INT32 i;
		boolean foundgoop = false;
		INT32 closestNum;
		// Looks for players in goop. If you find one, try to jump on him.
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (players[i].powers[pw_ingoop])
			{
				closestNum = -1;
				closestdist = 16384*FRACUNIT; // Just in case...
				// Find waypoint he is closest to
				for (th = thinkercap.next; th != &thinkercap; th = th->next)
				{
					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
						continue;
					mo2 = (mobj_t *)th;
					if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint)
					{
						dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y);
						if (closestNum == -1 || dist < closestdist)
						{
							closestNum = (mo2->spawnpoint->options & 7);
							closestdist = dist;
							foundgoop = true;
						}
					}
				}
				waypointNum = closestNum;
				break;
			}
		}
		if (!foundgoop)
		{
			if (mobj->z > 1056*FRACUNIT)
				waypointNum = 0;
			else
				waypointNum = 1 + (P_Random() % 4);
		}
		// Don't jump to the center when health is low.
		// Force the player to beat you with missiles.
		if (mobj->health <= 2 && waypointNum == 0)
			waypointNum = 1 + (P_Random() %4);
		if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT
			&& mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum)
		{
			if (P_Random() & 1)
				waypointNum++;
			else
				waypointNum--;
			waypointNum %= 5;
			if (waypointNum < 0)
				waypointNum = 0;
		}
		if (waypointNum == 0 && mobj->health <= 2)
			waypointNum = 1 + (P_Random() & 1);
		// scan the thinkers to find
		// the waypoint to use
		for (th = thinkercap.next; th != &thinkercap; th = th->next)
		{
			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
				continue;
			mo2 = (mobj_t *)th;
			if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum)
			{
				hitspot = mo2;
				break;
			}
		}
		if (hitspot == NULL)
		{
			CONS_Printf("BlackEggman unable to find waypoint #%d!\n", waypointNum);
			P_SetMobjState(mobj, mobj->info->spawnstate);
			return;
		}
		P_SetTarget(&mobj->tracer, hitspot);
		mobj->angle = R_PointToAngle2(mobj->x, mobj->y, hitspot->x, hitspot->y);
		an = mobj->angle;
		an >>= ANGLETOFINESHIFT;
		dist = P_AproxDistance(hitspot->x - mobj->x, hitspot->y - mobj->y);
		horizontal = dist / airtime;
		vertical = (gravity*airtime)/2;
		mobj->momx = FixedMul(horizontal, FINECOSINE(an));
		mobj->momy = FixedMul(horizontal, FINESINE(an));
		mobj->momz = vertical;
//		mobj->momz = 10*FRACUNIT;
	}
	else if (mobj->state == &states[S_BLACKEGG_JUMP2] && mobj->z <= mobj->floorz)
	{
		// BANG! onto the ground
		INT32 i,j;
		fixed_t ns;
		fixed_t x,y,z;
		mobj_t *mo2;
		S_StartSound(0, sfx_befall);
		z = mobj->floorz;
		for (j = 0; j < 2; j++)
		{
			for (i = 0; i < 32; i++)
			{
				const angle_t fa = (i*FINEANGLES/16) & FINEMASK;
				ns = 64 * FRACUNIT;
				x = mobj->x + FixedMul(FINESINE(fa),ns);
				y = mobj->y + FixedMul(FINECOSINE(fa),ns);
				mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE);
				ns = 16 * FRACUNIT;
				mo2->momx = FixedMul(FINESINE(fa),ns);
				mo2->momy = FixedMul(FINECOSINE(fa),ns);
			}
			z -= 32*FRACUNIT;
		}
		// Hurt player??
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;
			if (!players[i].mo)
				continue;
			if (players[i].mo->health <= 0)
				continue;
			if (P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y) > mobj->radius*4)
				continue;
			if (players[i].mo->z > mobj->z + 128*FRACUNIT)
				continue;
			if (players[i].mo->z < mobj->z - 64*FRACUNIT)
				continue;
			P_DamageMobj(players[i].mo, mobj, mobj, 1);
			// Laugh
			S_StartSound(0, sfx_bewar1 + (P_Random() % 4));
		}
		P_SetMobjState(mobj, mobj->info->spawnstate);
	}
	else if (mobj->state == &states[mobj->info->deathstate] && mobj->tics == mobj->state->tics)
	{
		S_StartSound(0, sfx_bedie1 + (P_Random() & 1));
	}
} |  | 
P_SpawnMobj
ERZ3 mode
If TypeofLevel has ERZ3 (value 2048) set, all objects will have their destscale set to 50 upon spawning (half their regular size), except for the following:
- MT_BLACKEGGMAN- Brak Eggman
- MT_BLACKEGGMAN_GOOPFIRE- Brak Eggman's Goop
- MT_BLACKEGGMAN_HELPER- Brak Eggman's Helper Object (The part of Brak Eggman you can stand on)
- MT_BLACKEGGMAN_MISSILE- Brak Eggman's Missile
- MT_SMOK- Smoke particle
- MT_GOOP- Egg Slimer's Goop
- MT_POP- Large Bubble Popping Object
Objects that are given MF_NOBLOCKMAP:
Objects that are given MF_NOCLIPHEIGHT when spawned:
- MT_RING- Ring
- MT_COIN- Coin
- MT_BLUEBALL- Blue Sphere (If- BLUE_SPHERESis defined)
- MT_THOK- Thok Object
- MT_GHOST- Ghost Object
| 
|  Code - P_SpawnMobj |  
|  |  
| //
// P_SpawnMobj
//
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{
	const mobjinfo_t *info = &mobjinfo[type];
	state_t *st;
	mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
	mobj->type = type;
	mobj->info = info;
	mobj->x = x;
	mobj->y = y;
	mobj->radius = info->radius;
	mobj->height = info->height;
	mobj->flags = info->flags;
	mobj->health = info->spawnhealth;
	mobj->reactiontime = info->reactiontime;
	mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer
	// do not set the state with P_SetMobjState,
	// because action routines can not be called yet
	st = &states[info->spawnstate];
	mobj->state = st;
	mobj->tics = st->tics;
	mobj->sprite = st->sprite;
	mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits..
	mobj->friction = ORIG_FRICTION;
	mobj->movefactor = ORIG_FRICTION_FACTOR;
	// All mobjs are created at 100% scale.
	mobj->scale = 100;
	mobj->destscale = mobj->scale;
	mobj->scalespeed = 8;
	// TODO: Make this a special map header
	if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN || mobj->type == MT_BLACKEGGMAN_GOOPFIRE
		|| mobj->type == MT_BLACKEGGMAN_HELPER || mobj->type == MT_BLACKEGGMAN_MISSILE
		|| mobj->type == MT_SMOK || mobj->type == MT_GOOP || mobj->type == MT_POP))
	{
		mobj->destscale = 50;
	}
	switch (mobj->type)
	{
		case MT_BLACKEGGMAN:
			{
				mobj_t *spawn = P_SpawnMobj(mobj->x, mobj->z, mobj->z+mobj->height-16*FRACUNIT, MT_BLACKEGGMAN_HELPER);
				P_SetTarget(&spawn->target, mobj);
			}
			break;
		case MT_DETON:
			mobj->movedir = 0;
			break;
		case MT_EGGGUARD:
			{
				mobj_t *spawn = P_SpawnMobj(x, y, z, MT_EGGSHIELD);
				P_SetTarget(&mobj->tracer, spawn);
				P_SetTarget(&spawn->tracer, mobj);
			}
			break;
		case MT_BIRD:
		case MT_BUNNY:
		case MT_MOUSE:
		case MT_CHICKEN:
		case MT_COW:
			mobj->fuse = 300 + (P_Random() % 50);
			break;
		case MT_REDRING: // Make MT_REDRING red by default
			mobj->flags |= MF_TRANSLATION;
			mobj->color = 6;
			break;
		case MT_SMALLBUBBLE: // Bubbles eventually dissipate, in case they get caught somewhere.
		case MT_MEDIUMBUBBLE:
		case MT_EXTRALARGEBUBBLE:
			mobj->fuse += 30 * TICRATE;
			break;
		case MT_BUSH:
		case MT_BERRYBUSH:
		case MT_THZPLANT:
		case MT_GFZFLOWER1:
		case MT_GFZFLOWER2:
		case MT_GFZFLOWER3:
		case MT_CEZFLOWER:
		case MT_SEAWEED:
		case MT_CORAL1:
		case MT_CORAL2:
		case MT_CORAL3:
//			if (!modifiedgame) // Speedup, if the game is not modified.
				mobj->flags |= MF_NOBLOCKMAP;
			break;
		case MT_REDTEAMRING:
			mobj->flags |= MF_TRANSLATION;
			mobj->color = 6;
			mobj->flags |= MF_NOCLIPHEIGHT;
			break;
		case MT_BLUETEAMRING:
			mobj->flags |= MF_TRANSLATION;
			mobj->color = 7;
			mobj->flags |= MF_NOCLIPHEIGHT;
			break;
		case MT_RING:
		case MT_COIN:
#ifdef BLUE_SPHERES
		case MT_BLUEBALL:
#endif
			nummaprings++;
		case MT_BOUNCERING:
		case MT_RAILRING:
		case MT_AUTOMATICRING:
		case MT_EXPLOSIONRING:
		case MT_SCATTERRING:
		case MT_GRENADERING:
		case MT_BOUNCEPICKUP:
		case MT_RAILPICKUP:
		case MT_AUTOPICKUP:
		case MT_EXPLODEPICKUP:
		case MT_SCATTERPICKUP:
		case MT_GRENADEPICKUP:
		case MT_NIGHTSWING:
		case MT_BLUEORB:
		case MT_BLACKORB:
		case MT_WHITEORB:
		case MT_YELLOWORB:
		case MT_GREENORB:
		case MT_THOK:
		case MT_GHOST:
			mobj->flags |= MF_NOCLIPHEIGHT;
		default:
			break;
	}
	// set subsector and/or block links
	P_SetThingPosition(mobj);
	mobj->floorz = mobj->subsector->sector->floorheight;
	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
	if (z == ONFLOORZ)
	{
		// defaults onground
		mobj->eflags |= MFE_ONGROUND;
		if ((mobj->type == MT_RING || mobj->type == MT_COIN || mobj->type == MT_REDTEAMRING || mobj->type == MT_BLUETEAMRING ||
			mobj->type == MT_BOUNCERING || mobj->type == MT_RAILRING || mobj->type == MT_AUTOMATICRING ||
			mobj->type == MT_EXPLOSIONRING || mobj->type == MT_SCATTERRING || mobj->type == MT_GRENADERING ||
			mobj->type == MT_BOUNCEPICKUP || mobj->type == MT_RAILPICKUP || mobj->type == MT_AUTOPICKUP ||
			mobj->type == MT_EXPLODEPICKUP || mobj->type == MT_SCATTERPICKUP || mobj->type == MT_GRENADEPICKUP
			|| mobj->type == MT_EMMY)
			&& mobj->flags & MF_AMBUSH)
			mobj->z = mobj->floorz + 32*FRACUNIT;
		else
			mobj->z = mobj->floorz;
	}
	else if (z == ONCEILINGZ)
		mobj->z = mobj->ceilingz - mobj->height;
	else
		mobj->z = z;
	if (!(mobj->type & MF_NOTHINK))
	{
		mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
		P_AddThinker(&mobj->thinker);
	}
	// Call action functions when the state is set
	if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC))
	{
		if (levelloading)
		{
			// Cache actions in a linked list
			// with function pointer, and
			// var1 & var2, which will be executed
			// when the level finishes loading.
			P_AddCachedAction(mobj, mobj->info->spawnstate);
		}
		else
		{
			var1 = st->var1;
			var2 = st->var2;
			st->action.acp1(mobj);
		}
	}
	if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP))
		P_CheckGravity(mobj, false);
	// Make sure scale matches destscale when spawned
	P_SetScale(mobj, mobj->destscale);
	return mobj;
} |  | 
p_polyobj.c/p_polyobj.h
BYTEANGLEMUL = (ANGLE_11hh/8)
- = 134217728/8
- = 16777216 (or 256*65536)
 
POLYOBJ_ANCHOR_DOOMEDNUM = 760 (PolyObject Anchor)
POLYOBJ_SPAWN_DOOMEDNUM = 761 (PolyObject Spawn Point)
POLYOBJ_SPAWNCRUSH_DOOMEDNUM = 762 (PolyObject Spawn Point (Crush))
POLYOBJ_START_LINE = 20 (Linedef Type 20, PolyObject - First Line)
POLYOBJ_EXPLICIT_LINE = 21 (Linedef Type 21, PolyObject - Explicitly Include Line)
POLYINFO_SPECIALNUM = 22 (Linedef Type 22, PolyObject - Parameters)
PolyObject Flags
| PolyObject Flags | 
| Flag Name | Value (Hex) | Value (Dec) | Description | 
| POF_CLIPLINES | 1 | 1 | Test against lines for collision | 
| POF_CLIPPLANES | 2 | 2 | Test against tops and bottoms for collision | 
| POF_SOLID | 3 | 3 | ( POF_CLIPLINES+POF_CLIPPLANES) Clips things | 
| POF_TESTHEIGHT | 4 | 4 | Test line collision with heights | 
| POF_RENDERSIDES | 8 | 8 | Render the sides | 
| POF_RENDERTOP | 10 | 16 | Render the top | 
| POF_RENDERBOTTOM | 20 | 32 | Render the bottom | 
| POF_RENDERPLANES | 30 | 48 | ( POF_RENDERTOP+POF_RENDERBOTTOM) Render top and bottom | 
| POF_RENDERALL | 38 | 56 | ( POF_RENDERSIDES+POF_RENDERPLANES) Renders everything | 
| POF_INVERT | 40 | 64 | Inverts collision (like a cage) | 
| POF_INVERTPLANES | 80 | 128 | Render inside planes | 
| POF_INVERTPLANESONLY | 100 | 256 | Only render inside planes | 
| POF_PUSHABLESTOP | 200 | 512 | Pushables (e.g. Gargoyle) will stop movement | 
| POF_LDEXEC | 400 | 1024 | This PO triggers a linedef executor | 
| POF_ONESIDE | 800 | 2048 | Only use the first side of the linedef | 
| POF_NOSPECIALS | 1000 | 4096 | Don't apply sector specials | 
Linedef Type 20 Flag settings
| Linedef Flags | PolyObject Flags | 
| (none) | POF_SOLID;POF_TESTHEIGHT;POF_RENDERSIDES | 
| Effect 1 | + POF_ONESIDE | 
| Effect 2 | - POF_SOLID | 
| Effect 3 | + POF_PUSHABLESTOP | 
| Effect 4 | + POF_RENDERPLANES | 
| Effect 5 | - POF_CLIPPLANES | 
| Not Climbable | + POF_LDEXEC | 
p_saveg.c
Sector Data
| Sector Data flags | 
| Decimal | Hexadecimal | Flag Name | Description | 
| 1 | 0x01 | SD_FLOORHT | Floor Height Data | 
| 2 | 0x02 | SD_CEILHT | Ceiling Height Data | 
| 4 | 0x04 | SD_FLOORPIC | Floor Flat Data | 
| 8 | 0x08 | SD_CEILPIC | Ceiling Flat Data | 
| 16 | 0x10 | SD_LIGHT | Sector Brightness Data | 
| 32 | 0x20 | SD_SPECIAL | Sector Specials Data | 
| 64 | 0x40 | SD_DIFF2 | Sector Diff2 Data (Set if any of the Sector Diff2 flags have been set) | 
| Sector Diff2 flags | 
| Decimal | Hexadecimal | Flag Name | Description | 
| 1 | 0x01 | SD_FXOFFS | Floor Flat X Offset Data (Set if Linedef type 7, Flat Alignment has been used to change this offset) | 
| 2 | 0x02 | SD_FYOFFS | Floor Flat Y Offset Data (Set if Linedef type 7, Flat Alignment has been used to change this offset) | 
| 4 | 0x04 | SD_CXOFFS | Ceiling Flat X Offset Data (Set if Linedef type 7, Flat Alignment has been used to change this offset) | 
| 8 | 0x08 | SD_CYOFFS | Ceiling Flat Y Offset Data (Set if Linedef type 7, Flat Alignment has been used to change this offset) | 
| 16 | 0x10 | SD_TAG | Sector Tag Data (Set if the sector has a sector tag) | 
| 32 | 0x20 | SD_FLOORANG | Floor Flat Angle Data (Set if Linedef type 7, Flat Alignment has been used to change the angle) | 
| 64 | 0x40 | SD_CEILANG | Ceiling Flat Angle Data (Set if Linedef type 7, Flat Alignment has been used to change the angle) | 
Linedef Data
| Linedef Data flags | 
| Decimal | Hexadecimal | Flag Name | Description | 
| 1 | 0x01 | LD_FLAG | Linedef Flags Data | 
| 2 | 0x02 | LD_SPECIAL | Linedef Special Data | 
| 8 | 0x08 | LD_S1TEXOFF | Front Side Texture Offset Data | 
| 16 | 0x10 | LD_S1TOPTEX | Front Side Upper Texture Data | 
| 32 | 0x20 | LD_S1BOTTEX | Front Side Lower Texture Data | 
| 64 | 0x40 | LD_S1MIDTEX | Front Side Middle Texture Data | 
| 128 | 0x80 | LD_DIFF2 | Linedef Diff2 Data (Set if any of the Linedef Diff2 flags have been set) | 
| Linedef Diff2 flags | 
| Decimal | Hexadecimal | Flag Name | Description | 
| 1 | 0x01 | LD_S2TEXOFF | Back Side Texture Offset Data | 
| 2 | 0x02 | LD_S2TOPTEX | Back Side Upper Texture Data | 
| 4 | 0x04 | LD_S2BOTTEX | Back Side Lower Texture Data | 
| 8 | 0x08 | LD_S2MIDTEX | Back Side Middle Texture Data | 
mobj_diff_t (Mobj Data)
| mobj_diff_t | 
| Decimal | Hexadecimal | Flag Name | Description | 
| 1 | 0x0000001 | MD_SPAWNPOINT | Mobj Spawnpoint Data | 
| 2 | 0x0000002 | MD_POS | Mobj Position Data | 
| 4 | 0x0000004 | MD_TYPE | Mobj Thing Type Number Data | 
| 8 | 0x0000008 | MD_MOM | Mobj Momentum Data (Set if the mobj is moving) | 
| 16 | 0x0000010 | MD_RADIUS | Mobj Radius Data (Set if the mobj's radius is changed) | 
| 32 | 0x0000020 | MD_HEIGHT | Mobj Height Data (Set if the mobj's height is changed) | 
| 64 | 0x0000040 | MD_FLAGS | Mobj FLAGSData (Set if the mobj'sFLAGSare changed, or if the mobj hasMF_TRANSLATION) | 
| 128 | 0x0000080 | MD_HEALTH | Mobj Health Data (Set if the mobj's health changes) | 
| 256 | 0x0000100 | MD_RTIME | Mobj Reaction time Data (Set if the mobj's reaction time changes) | 
| 512 | 0x0000200 | MD_STATE | Mobj State Data (Set if the mobj's state changes) | 
| 1024 | 0x0000400 | MD_TICS | Mobj Tics Data (Set if the mobj's tics change) | 
| 2048 | 0x0000800 | MD_SPRITE | Mobj Sprite Data (Set if the mobj's sprite changes) | 
| 4096 | 0x0001000 | MD_FRAME | Mobj Frame Data (Set if the mobj's frame changes) | 
| 8192 | 0x0002000 | MD_EFLAGS | Mobj Extra Flags Data (Set if the mobj has any extra flags set) | 
| 16384 | 0x0004000 | MD_PLAYER | Mobj Player Data (Set if the mobj is a Player) | 
| 32768 | 0x0008000 | MD_MOVDIR | Mobj Movement direction Data | 
| 65536 | 0x0010000 | MD_MOVECOUNT | Mobj Movecount Data | 
| 131072 | 0x0020000 | MD_THRESHOLD | Mobj Threshold Data | 
| 262144 | 0x0040000 | MD_LASTLOOK | Mobj Lastlook Data (Set if the mobj's lastlook is not -1) | 
| 524288 | 0x0080000 | MD_TARGET | Mobj Target Data (Set if the mobj has a target) | 
| 1048576 | 0x0100000 | MD_TRACER | Mobj Tracer Data (Set if the mobj has a tracer) | 
| 2097152 | 0x0200000 | MD_FRICTION | Mobj Friction Data (Set if the mobj's friction is not ORIG_FRICTION) | 
| 4194304 | 0x0400000 | MD_MOVEFACTOR | Mobj Movement factor Data (Set if the mobj's movefactor is not ORIG_FRICTION_FACTOR) | 
| 8388608 | 0x0800000 | MD_FLAGS2 | Mobj FLAGS2Data | 
| 16777216 | 0x1000000 | MD_FUSE | Mobj Fuse Data | 
| 33554432 | 0x2000000 | MD_WATERTOP | Mobj Watertop Data | 
| 67108864 | 0x4000000 | MD_WATERBOTTOM | Mobj Waterbottom Data | 
| 134217728 | 0x8000000 | MD_SCALE | Mobj Scale Data (Set if the mobj's scale is not 100) | 
| 268435456 | 0x10000000 | MD_DSCALE | Mobj Destination scale Data (Set if the mobj's destscale is not the same as it's scale) | 
| 536870912 | 0x20000000 | MD_BLUEFLAG | Blue Flag Data (Set if the mobj is a CTF Blue Flag) | 
| 1073741824 | 0x40000000 | MD_REDFLAG | Red Flag Data (Set if the mobj is a CTF Red Flag) | 
p_setup.c
P_SpawnSecretItems
Position of RedXVI:
x = 04220000000*-1
- = 574619648*-1
- = -8768
 
y = 0554000000*-1
- = 95420416*-1
- = -1456
 
z = ONFLOORZ
| 
|  Code - P_SpawnSecretItems |  
|  |  
| void P_SpawnSecretItems(boolean loademblems)
{
	// Now let's spawn those funky emblem things! Tails 12-08-2002
	if (netgame || multiplayer || (modifiedgame && !savemoddata) || timeattacking) // No cheating!!
		return;
	if (loademblems)
		P_SpawnEmblems();
	if(gamemap == 11)
		P_SpawnMobj(04220000000*-1, 0554000000*-1, ONFLOORZ, MT_PXVI)->angle = ANGLE_270;
} |  | 
p_spec.c/p_spec.h
SCROLL_SHIFT = 5 (Amount (dx, dy) vector linedef is shifted right to get scroll amount)
CARRYFACTOR = (3*FRACUNIT)/32
- = 3 fracunits/32 tics (Factor to scale scrolling effect into mobj-carrying properties = 3/32)
 
MAXANIMS = 64
Linedef Types 489 and 490
| Linedef Flags | Linedef type 489 | Linedef type 490 | 
| None | + POF_NOSPECIALS;-
 POF_RENDERALL;-
 POF_SOLID | - POF_NOSPECIALS;+
 POF_RENDERALL;+
 POF_SOLID | 
| Not Climbable | + POF_NOSPECIALS;-
 POF_RENDERALL | - POF_NOSPECIALS;+
 POF_RENDERALL | 
VDOORSPEED = FRACUNIT*2/NEWTICRATERATIO
- = FRACUNIT*2
- = 2 fracunits/1 tic
 
length = Linedef's length
friction = (0x1EB8*length)/0x80 + 0xD000
- = (7864*length)/128 + 53248
- = (983*length)/16 + 53248
 
If friction > ORIG_FRICTION (Ice):
- movefactor= ((- 0x10092-- friction)*(- 0x70))/- 0x158- = ((65682 - friction)*(112))/344
- = ((65682 - friction)*14)/43
 
If friction <= ORIG_FRICTION (Sludge):
- movefactor= ((- friction-- 0xDB34)*(- 0xA))/- 0x80- = ((friction- 56116)*(10))/128
- = ((friction- 56116)*5)/64
 
if (friction > FRACUNIT)
- friction=- FRACUNIT;
if (friction < 0)
- friction= 0;
if (movefactor < 32)
- movefactor= 32;
| Linedef length | friction | movefactor | 
| 1 | 53309.4375 | -219.2626953125 = 32
 | 
| 50 | 56319.875 | 15.927734375 = 32
 | 
| 53.34852492~ | 56525.6 | 32 | 
| 100 | 59391.75 | 255.91796875 | 
| 100.004069~ | 59392 ( ORIG_FRICTION) | 255.9375 | 
| 101 | 59453.1875 | 2027.98546511~ | 
| 150 | 62463.625 | 495.908203125 | 
| 200 | 65535.5 | 47.69767442~ | 
| 200.00813835~ | 65536 ( FRACUNIT) | 47.53488372~ | 
PUSH_FACTOR = 7
GLOWSPEED = 8
STROBEBRIGHT = 5
FASTDARK = 15
SLOWDARK = 35
CEILSPEED = (FRACUNIT/NEWTICRATERATIO)
- = FRACUNIT
- = 1 fracunit/ 1 tic
 
ELEVATORSPEED = (FRACUNIT*4/NEWTICRATERATIO)
- = FRACUNIT*4
- = 4 fracunits/1 tic
 
FLOORSPEED = (FRACUNIT/NEWTICRATERATIO)
- = FRACUNIT
- = 1 fracunit/1 tic
 
ORIG_FRICTION = (0xE8 << (FRACBITS-8))
- = 232 * 2^16-8
- = 232 * 2^8
- = 232 * 256
- = 59392
 
ORIG_FRICTION_FACTOR = (8 << (FRACBITS-8))
- = 8 * 2^16-8
- = 8 * 2^8
- = 8 * 256
- = 2048
 
Add_Pusher
- <<(FRACBITS-PUSH_FACTOR)
- = *2^(16-7)
- = *2^9
- = *512
- <<(FRACBITS+1)
- = *2^(16+1)
- = *2^17
- = *131072
| 
|  Code - Add_Pusher |  
|  |  
| /** Adds a pusher.
  *
  * \param type     Type of push/pull effect.
  * \param x_mag    X magnitude.
  * \param y_mag    Y magnitude.
  * \param source   For a point pusher/puller, the source object.
  * \param affectee Target sector.
  * \param referrer What sector set it
  * \sa T_Pusher, P_GetPushThing, P_SpawnPushers
  */
static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *source, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider)
{
	pusher_t *p = Z_Calloc(sizeof *p, PU_LEVSPEC, NULL);
	p->thinker.function.acp1 = (actionf_p1)T_Pusher;
	p->source = source;
	p->type = type;
	p->x_mag = x_mag>>FRACBITS;
	p->y_mag = y_mag>>FRACBITS;
	p->exclusive = exclusive;
	p->slider = slider;
	if (referrer != -1)
	{
		p->roverpusher = true;
		p->referrer = referrer;
	}
	else
		p->roverpusher = false;
	// "The right triangle of the square of the length of the hypotenuse is equal to the sum of the squares of the lengths of the other two sides."
	// "Bah! Stupid brains! Don't you know anything besides the Pythagorean Theorem?" - Earthworm Jim
	if (type == p_downcurrent || type == p_upcurrent || type == p_upwind || type == p_downwind)
		p->magnitude = P_AproxDistance(p->x_mag,p->y_mag)<<(FRACBITS-PUSH_FACTOR);
	else
		p->magnitude = P_AproxDistance(p->x_mag,p->y_mag);
	if (source) // point source exist?
	{
		// where force goes to zero
		if (type == p_push)
			p->radius = AngleFixed(source->angle);
		else
			p->radius = (p->magnitude)<<(FRACBITS+1);
		p->x = p->source->x;
		p->y = p->source->y;
		p->z = p->source->z;
	}
	p->affectee = affectee;
	P_AddThinker(&p->thinker);
} |  | 
T_Pusher
Touching the ground (while in FOF):
- Wind - Half force
- Current - Full force
Anywhere else in FOF:
- Wind - Full force
- Current - Full force
- <<(FRACBITS-PUSH_FACTOR)
- = *2^(16-7)
- = *2^9
- = *512
| 
|  Code - T_Pusher |  
|  |  
| /** Applies a pusher to all affected objects.
  *
  * \param p Thinker for the pusher effect.
  * \todo Split up into multiple functions.
  * \sa Add_Pusher, PIT_PushThing
  */
void T_Pusher(pusher_t *p)
{
	sector_t *sec;
	mobj_t *thing;
	msecnode_t *node;
	INT32 xspeed = 0,yspeed = 0;
	INT32 xl, xh, yl, yh, bx, by;
	INT32 radius;
	//INT32 ht = 0;
	boolean inFOF;
	boolean touching;
	boolean foundfloor = false;
	boolean moved;
	xspeed = yspeed = 0;
	sec = sectors + p->affectee;
	// Be sure the special sector type is still turned on. If so, proceed.
	// Else, bail out; the sector type has been changed on us.
	if (p->roverpusher)
	{
		sector_t *referrer = §ors[p->referrer];
		if (GETSECSPECIAL(referrer->special, 3) == 2
			|| GETSECSPECIAL(referrer->special, 3) == 3)
			foundfloor = true;
	}
	else if (!(GETSECSPECIAL(sec->special, 3) == 2
			|| GETSECSPECIAL(sec->special, 3) == 3))
		return;
	if (p->roverpusher && foundfloor == false) // Not even a 3d floor has the PUSH_MASK.
		return;
	// For constant pushers (wind/current) there are 3 situations:
	//
	// 1) Affected Thing is above the floor.
	//
	//    Apply the full force if wind, no force if current.
	//
	// 2) Affected Thing is on the ground.
	//
	//    Apply half force if wind, full force if current.
	//
	// 3) Affected Thing is below the ground (underwater effect).
	//
	//    Apply no force if wind, full force if current.
	//
	// Apply the effect to clipped players only for now.
	//
	// In Phase II, you can apply these effects to Things other than players.
	if (p->type == p_push)
	{
		// Seek out all pushable things within the force radius of this
		// point pusher. Crosses sectors, so use blockmap.
		tmpusher = p; // MT_PUSH/MT_PULL point source
		radius = p->radius; // where force goes to zero
		tmbbox[BOXTOP]    = p->y + radius;
		tmbbox[BOXBOTTOM] = p->y - radius;
		tmbbox[BOXRIGHT]  = p->x + radius;
		tmbbox[BOXLEFT]   = p->x - radius;
		xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
		xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
		yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
		yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
		for (bx = xl; bx <= xh; bx++)
			for (by = yl; by <= yh; by++)
				P_BlockThingsIterator(bx,by, PIT_PushThing);
		return;
	}
	// constant pushers p_wind and p_current
	node = sec->touching_thinglist; // things touching this sector
	for (; node; node = node->m_snext)
	{
		thing = node->m_thing;
		if (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)
			&& !(thing->type == MT_SMALLBUBBLE
											|| thing->type == MT_MEDIUMBUBBLE
											|| thing->type == MT_EXTRALARGEBUBBLE))
			continue;
		if (!(thing->flags & MF_PUSHABLE) && !(thing->type == MT_PLAYER
											|| thing->type == MT_SMALLBUBBLE
											|| thing->type == MT_MEDIUMBUBBLE
											|| thing->type == MT_EXTRALARGEBUBBLE
											|| thing->type == MT_LITTLETUMBLEWEED
											|| thing->type == MT_BIGTUMBLEWEED))
			continue;
		if (thing->flags2 & MF2_PUSHED)
			continue;
		if (thing->player && (thing->player->pflags & PF_ROPEHANG || thing->player->pflags & PF_MINECART))
			continue;
		if (thing->player && (thing->state == &states[thing->info->painstate]) && (thing->player->powers[pw_flashing] > (flashingtics/4)*3 && thing->player->powers[pw_flashing] <= flashingtics))
			continue;
		inFOF = touching = moved = false;
		// Find the area that the 'thing' is in
		if (p->roverpusher)
		{
			sector_t *referrer = §ors[p->referrer];
			INT32 special;
			special = GETSECSPECIAL(referrer->special, 3);
			if (!(special == 2 || special == 3))
				return;
			if (thing->eflags & MFE_VERTICALFLIP)
			{
				if (referrer->floorheight > thing->z + thing->height
					|| referrer->ceilingheight < (thing->z + (thing->height >> 1)))
					return;
				if (thing->z < referrer->floorheight)
					touching = true;
				if (thing->z + (thing->height >> 1) > referrer->floorheight)
					inFOF = true;
			}
			else
			{
				if (referrer->ceilingheight < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
					return;
				if (thing->z + thing->height > referrer->ceilingheight)
					touching = true;
				if (thing->z + (thing->height >> 1) < referrer->ceilingheight)
					inFOF = true;
			}
		}
		else // Treat the entire sector as one big FOF
		{
			if (thing->z == thing->subsector->sector->floorheight)
				touching = true;
			else if (p->type != p_current)
				inFOF = true;
		}
		if (!touching && !inFOF) // Object is out of range of effect
			continue;
		if (p->type == p_wind)
		{
			if (touching) // on ground
			{
				xspeed = (p->x_mag)>>1; // half force
				yspeed = (p->y_mag)>>1;
				moved = true;
			}
			else if (inFOF)
			{
				xspeed = (p->x_mag); // full force
				yspeed = (p->y_mag);
				moved = true;
			}
		}
		else if (p->type == p_upwind)
		{
			if (touching) // on ground
			{
				thing->momz += (p->magnitude)>>1;
				moved = true;
			}
			else if (inFOF)
			{
				thing->momz += p->magnitude;
				moved = true;
			}
		}
		else if (p->type == p_downwind)
		{
			if (touching) // on ground
			{
				thing->momz -= (p->magnitude)>>1;
				moved = true;
			}
			else if (inFOF)
			{
				thing->momz -= p->magnitude;
				moved = true;
			}
		}
		else // p_current
		{
			if (!touching && !inFOF) // Not in water at all
				xspeed = yspeed = 0; // no force
			else // underwater / touching water
			{
				if (p->type == p_upcurrent)
					thing->momz += p->magnitude;
				else if (p->type == p_downcurrent)
					thing->momz -= p->magnitude;
				else
				{
					xspeed = p->x_mag; // full force
					yspeed = p->y_mag;
				}
				moved = true;
			}
		}
		if (p->type != p_downcurrent && p->type != p_upcurrent
			&& p->type != p_upwind && p->type != p_downwind)
		{
			thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR);
			thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR);
			if (thing->player)
			{
				thing->player->cmomx += xspeed<<(FRACBITS-PUSH_FACTOR);
				thing->player->cmomy += yspeed<<(FRACBITS-PUSH_FACTOR);
				thing->player->cmomx = FixedMul(thing->player->cmomx, ORIG_FRICTION);
				thing->player->cmomy = FixedMul(thing->player->cmomy, ORIG_FRICTION);
			}
			// Tumbleweeds bounce a bit...
			if (thing->type == MT_LITTLETUMBLEWEED || thing->type == MT_BIGTUMBLEWEED)
				thing->momz += P_AproxDistance(xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)) >> 2;
		}
		if (moved)
		{
			if (p->slider && thing->player)
			{
				boolean jumped = (thing->player->pflags & PF_JUMPED);
				P_ResetPlayer (thing->player);
				if (jumped)
					thing->player->pflags |= PF_JUMPED;
				thing->player->pflags |= PF_SLIDING;
				P_SetPlayerMobjState (thing, thing->info->painstate); // Whee!
				thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR));
				if (thing->player == &players[consoleplayer])
					localangle = thing->angle;
				else if (splitscreen && thing->player == &players[secondarydisplayplayer])
					localangle2 = thing->angle;
			}
			if (p->exclusive)
				thing->flags2 |= MF2_PUSHED;
		}
	}
} |  | 
p_user.c
MAXBOB = 0x10<<FRACBITS
- = 16 * 2^16
- = 16 * 65536
- = 16*FRACUNIT
- = 16 fracunits (Maximum height the camera "bobs" when walking/running with 1st person camera)
 
SPACESPECIAL = 12 (Sector Type 12, Space Countdown)
MAXDRILLSPEED = 14000 (Maximum drilling speed as NiGHTS Super Sonic)
MAXNORMALSPEED = 6000 (Maximum flying speed as NiGHTS Super Sonic)
P_GetPlayerHeight
Height = MT_PLAYER's Height
- = 56 fracunits
 
| 
|  Code - P_GetPlayerHeight |  
|  |  
| //
// P_GetPlayerHeight
//
// Returns the height
// of the player.
//
fixed_t P_GetPlayerHeight(player_t *player)
{
	return FIXEDSCALE(player->mo->info->height, player->mo->scale);
} |  | 
P_GetPlayerSpinHeight
Height = MT_PLAYER's Height/7*(FRACUNIT/4)
- = 56/1.75
- = 32 fracunits
 
| 
|  Code - P_GetPlayerSpinHeight |  
|  |  
| //
// P_GetPlayerSpinHeight
//
// Returns the 'spin height'
// of the player.
//
fixed_t P_GetPlayerSpinHeight(player_t *player)
{
	return FixedDiv(FIXEDSCALE(player->mo->info->height, player->mo->scale),7*(FRACUNIT/4));
} |  | 
P_DoJump
Momz = (jumpfactor*momz)/100
- = momz*(jumpfactor/100)
 
- Underwater: Momz * 0.585
- Quicksand: Momz/2
- 2D Mode: Momz*1.1
| Jump Momentum | 
|  | Z Momentum (fracunits) | 
| Condition | Normal | Underwater | Quicksand | 2D Mode | 2D Mode + Underwater | 2D Mode + Quicksand | 
| Default | ( jumpfactor*(39*(FRACUNIT/4)))/100*FRACUNIT=9.75*(
 jumpfactor/100) | ( jumpfactor*(39*(FRACUNIT/4)*(117/200)))/100*FRACUNIT=(9.75*0.585)*(
 jumpfactor/100)=5.70375*(
 jumpfactor/100) | ( jumpfactor*(39*(FRACUNIT/4)>>1))/100*FRACUNIT=(9.75/2)*(
 jumpfactor/100)=4.875*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(39*(FRACUNIT/4)))/100*FRACUNIT=9.75*(
 jumpfactor/100)*1.1=10.725*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(39*(FRACUNIT/4)*(117/200)))/100*FRACUNIT=(9.75*0.585)*((
 jumpfactor*1.1)/100)=5.70375*(
 jumpfactor/100)*1.1=6.274125*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(39*(FRACUNIT/4)>>1))/100*FRACUNIT=(9.75/2)*(
 jumpfactor/100)=4.875*(
 jumpfactor/100)*1.1=5.3625*(
 jumpfactor/100) | 
| Jumping from being carried ( PF_CARRIED/PF_ITEMHANG) | ( jumpfactor*(9*FRACUNIT))/100*FRACUNIT=9*(
 jumpfactor/100) | ( jumpfactor*(9*FRACUNIT*(117/200)))/100*FRACUNIT=(9*0.585)*(
 jumpfactor/100)=5.265*(
 jumpfactor/100) | ( jumpfactor*(9*FRACUNIT>>1))/100*FRACUNIT=(9/2)*(
 jumpfactor/100)=4.5*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(9*FRACUNIT))/100*FRACUNIT=9*(
 jumpfactor/100)*1.1=9.9*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(9*FRACUNIT*(117/200)))/100*FRACUNIT=(9.*0.585)*((
 jumpfactor*1.1)/100)=5.265*(
 jumpfactor/100)*1.1=5.7915*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(9*FRACUNIT>>1))/100*FRACUNIT=(9/2)*(
 jumpfactor/100)=4.5*(
 jumpfactor/100)*1.1=4.95*(
 jumpfactor/100) | 
| Jumping from Rope Hang ( PF_ROPEHANG) | ( jumpfactor*(12*FRACUNIT))/100*FRACUNIT=12*(
 jumpfactor/100) | ( jumpfactor*(12*FRACUNIT*(117/200)))/100*FRACUNIT=(12*0.585)*(
 jumpfactor/100)=7.02*(
 jumpfactor/100) | ( jumpfactor*(12*FRACUNIT>>1))/100*FRACUNIT=(12/2)*(
 jumpfactor/100)=6*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT))/100*FRACUNIT=12*(
 jumpfactor/100)*1.1=13.2*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT*(117/200)))/100*FRACUNIT=(12*0.585)*((
 jumpfactor*1.1)/100)=7.02*(
 jumpfactor/100)*1.1=7.722*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT>>1))/100*FRACUNIT=(12/2)*(
 jumpfactor/100)=6*(
 jumpfactor/100)*1.1=6.6*(
 jumpfactor/100) | 
| NiGHTS Mode | ( jumpfactor*(24*FRACUNIT))/100*FRACUNIT=24*(
 jumpfactor/100) | ( jumpfactor*(24*FRACUNIT*(117/200)))/100*FRACUNIT=(24*0.585)*(
 jumpfactor/100)=14.04*(
 jumpfactor/100) | ( jumpfactor*(24*FRACUNIT>>1))/100*FRACUNIT=(24/2)*(
 jumpfactor/100)=12*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(24*FRACUNIT))/100*FRACUNIT=24*(
 jumpfactor/100)*1.1=26.4*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(24*FRACUNIT*(117/200)))/100*FRACUNIT=(24*0.585)*((
 jumpfactor*1.1)/100)=14.04*(
 jumpfactor/100)*1.1=15.444*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(24*FRACUNIT>>1))/100*FRACUNIT=(24/2)*(
 jumpfactor/100)=12*(
 jumpfactor/100)*1.1=13.2*(
 jumpfactor/100) | 
| CA_DOUBLEJUMP+CA2_MULTIABILITY | ( jumpfactor*(23*(FRACUNIT/2)))/100*FRACUNIT=11.5*(
 jumpfactor/100) | ( jumpfactor*(23*(FRACUNIT/2)*(117/200)))/100*FRACUNIT=(11.5*0.585)*(
 jumpfactor/100)=6.7275*(
 jumpfactor/100) | ( jumpfactor*(23*(FRACUNIT/2)>>1))/100*FRACUNIT=(11.5/2)*(
 jumpfactor/100)=5.75*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(23*(FRACUNIT/2)))/100*FRACUNIT=11.5*(
 jumpfactor/100)*1.1=12.65*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(23*(FRACUNIT/2)*(117/200)))/100*FRACUNIT=(11.5*0.585)*((
 jumpfactor*1.1)/100)=6.7275*(
 jumpfactor/100)*1.1=7.40025*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(23*(FRACUNIT/2)>>1))/100*FRACUNIT=(11.5/2)*(
 jumpfactor/100)=5.75*(
 jumpfactor/100)*1.1=6.325*(
 jumpfactor/100) | 
| CA_FLOAT/CA_SLOWFALL+CA2_MULTIABILITY | ( jumpfactor*(12*FRACUNIT))/100*FRACUNIT=12*(
 jumpfactor/100) | ( jumpfactor*(12*FRACUNIT*(117/200)))/100*FRACUNIT=(12*0.585)*(
 jumpfactor/100)=7.02*(
 jumpfactor/100) | ( jumpfactor*(12*FRACUNIT>>1))/100*FRACUNIT=(12/2)*(
 jumpfactor/100)=6*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT))/100*FRACUNIT=12*(
 jumpfactor/100)*1.1=13.2*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT*(117/200)))/100*FRACUNIT=(12*0.585)*((
 jumpfactor*1.1)/100)=7.02*(
 jumpfactor/100)*1.1=7.722*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(12*FRACUNIT>>1))/100*FRACUNIT=(12/2)*(
 jumpfactor/100)=6*(
 jumpfactor/100)*1.1=6.6*(
 jumpfactor/100) | 
| Default (Super) | ( jumpfactor*(13*FRACUNIT))/100*FRACUNIT=13*(
 jumpfactor/100) | ( jumpfactor*(13*FRACUNIT*(117/200)))/100*FRACUNIT=(13*0.585)*(
 jumpfactor/100)=7.605*(
 jumpfactor/100) | ( jumpfactor*(13*FRACUNIT>>1))/100*FRACUNIT=(13/2)*(
 jumpfactor/100)=6.5*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(13*FRACUNIT))/100*FRACUNIT=13*(
 jumpfactor/100)*1.1=14.3*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(13*FRACUNIT*(117/200)))/100*FRACUNIT=(13*0.585)*((
 jumpfactor*1.1)/100)=7.605*(
 jumpfactor/100)*1.1=8.3655*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(13*FRACUNIT>>1))/100*FRACUNIT=(13/2)*(
 jumpfactor/100)=6.5*(
 jumpfactor/100)*1.1=7.15*(
 jumpfactor/100) | 
| CA_FLOAT(Super) | ( jumpfactor*(28*FRACUNIT))/100*FRACUNIT=28*(
 jumpfactor/100) | ( jumpfactor*(28*FRACUNIT*(117/200)))/100*FRACUNIT=(28*0.585)*(
 jumpfactor/100)=16.38*(
 jumpfactor/100) | ( jumpfactor*(28*FRACUNIT>>1))/100*FRACUNIT=(28/2)*(
 jumpfactor/100)=14*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(28*FRACUNIT))/100*FRACUNIT=28*(
 jumpfactor/100)*1.1=30.8*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(28*FRACUNIT*(117/200)))/100*FRACUNIT=(28*0.585)*((
 jumpfactor*1.1)/100)=16.38*(
 jumpfactor/100)*1.1=18.018*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(28*FRACUNIT>>1))/100*FRACUNIT=(28/2)*(
 jumpfactor/100)=14*(
 jumpfactor/100)*1.1=15.4*(
 jumpfactor/100) | 
| CA_SLOWFALL(Super) | ( jumpfactor*(37*(FRACUNIT/2)))/100*FRACUNIT=18.5*(
 jumpfactor/100) | ( jumpfactor*(37*(FRACUNIT/2)*(117/200)))/100*FRACUNIT=(18.5*0.585)*(
 jumpfactor/100)=10.8225*(
 jumpfactor/100) | ( jumpfactor*(37*(FRACUNIT/2)>>1))/100*FRACUNIT=(18.5/2)*(
 jumpfactor/100)=9.25*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(37*(FRACUNIT/2)))/100*FRACUNIT=18.5*(
 jumpfactor/100)*1.1=20.35*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(37*(FRACUNIT/2)*(117/200)))/100*FRACUNIT=(18.5*0.585)*((
 jumpfactor*1.1)/100)=10.8225*(
 jumpfactor/100)*1.1=11.90475*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(37*(FRACUNIT/2)>>1))/100*FRACUNIT=(18.5/2)*(
 jumpfactor/100)=9.25*(
 jumpfactor/100)*1.1=10.175*(
 jumpfactor/100) | 
| CA_FLOAT+CA2_MULTIABILITY(Super) | ( jumpfactor*(30*FRACUNIT))/100*FRACUNIT=30*(
 jumpfactor/100) | ( jumpfactor*(30*FRACUNIT*(117/200)))/100*FRACUNIT=(30*0.585)*(
 jumpfactor/100)=17.55*(
 jumpfactor/100) | ( jumpfactor*(30*FRACUNIT>>1))/100*FRACUNIT=(30/2)*(
 jumpfactor/100)=15*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(30*FRACUNIT))/100*FRACUNIT=30*(
 jumpfactor/100)*1.1=33*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(30*FRACUNIT*(117/200)))/100*FRACUNIT=(30*0.585)*((
 jumpfactor*1.1)/100)=17.55*(
 jumpfactor/100)*1.1=19.305*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(30*FRACUNIT>>1))/100*FRACUNIT=(30/2)*(
 jumpfactor/100)=15*(
 jumpfactor/100)*1.1=16.5*(
 jumpfactor/100) | 
| CA_SLOWFALL+CA2_MULTIABILITY(Super) | ( jumpfactor*(37*(FRACUNIT/2)+2*FRACUNIT))/100*FRACUNIT=20.5*(
 jumpfactor/100) | ( jumpfactor*((37*(FRACUNIT/2)+2*FRACUNIT)*(117/200)))/100*FRACUNIT=(20.5*0.585)*(
 jumpfactor/100)=11.9925*(
 jumpfactor/100) | ( jumpfactor*((37*(FRACUNIT/2)+2*FRACUNIT)>>1))/100*FRACUNIT=(20.5/2)*(
 jumpfactor/100)=10.25*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*(37*(FRACUNIT/2)+2*FRACUNIT))/100*FRACUNIT=20.5*(
 jumpfactor/100)*1.1=22.55*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*((37*(FRACUNIT/2)+2*FRACUNIT)*(117/200)))/100*FRACUNIT=(20.5*0.585)*((
 jumpfactor*1.1)/100)=11.9925*(
 jumpfactor/100)*1.1=13.19175*(
 jumpfactor/100) | (( jumpfactor+(jumpfactor/10))*((37*(FRACUNIT/2)+2*FRACUNIT)>>1))/100*FRACUNIT=(20.5/2)*(
 jumpfactor/100)=10.25*(
 jumpfactor/100)*1.1=11.275*(
 jumpfactor/100) | 
| 
|  Code - P_DoJump |  
|  |  
| //
// P_DoJump
//
// Jump routine for the player
//
void P_DoJump(player_t *player, boolean soundandstate)
{
	fixed_t factor;
	if (player->pflags & PF_STASIS || (player->powers[pw_nocontrol] && player->powers[pw_nocontrol] < 65536))
		return;
	if (!player->jumpfactor)
		return;
	if (player->powers[pw_ingoop])
		return;
	if (player->climbing)
	{
		// Jump this high.
		if (player->powers[pw_super])
			player->mo->momz = 5*FRACUNIT;
		else if (player->mo->eflags & MFE_UNDERWATER)
			player->mo->momz = 2*FRACUNIT;
		else
			player->mo->momz = 15*(FRACUNIT/4);
		player->mo->angle = player->mo->angle - ANGLE_180; // Turn around from the wall you were climbing.
		if (player == &players[consoleplayer])
			localangle = player->mo->angle; // Adjust the local control angle.
		else if (splitscreen && player == &players[secondarydisplayplayer])
			localangle2 = player->mo->angle;
		player->climbing = 0; // Stop climbing, duh!
		P_InstaThrust(player->mo, player->mo->angle, FIXEDSCALE(6*FRACUNIT, player->mo->scale)); // Jump off the wall.
	}
	else if (!(player->pflags & PF_JUMPED)) // Spin Attack
	{
		if (player->mo->ceilingz-player->mo->floorz <= player->mo->height-1)
			return;
		// Jump this high.
		if (player->pflags & PF_CARRIED)
		{
			player->mo->momz = 9*FRACUNIT;
			player->pflags &= ~PF_CARRIED;
		}
		else if (player->pflags & PF_ITEMHANG)
		{
			player->mo->momz = 9*FRACUNIT;
			player->pflags &= ~PF_ITEMHANG;
		}
		else if (player->pflags & PF_ROPEHANG)
		{
			player->mo->momz = 12*FRACUNIT;
			player->pflags &= ~PF_ROPEHANG;
			P_SetTarget(&player->mo->tracer, NULL);
		}
		else if (maptol & TOL_NIGHTS)
			player->mo->momz = 24*FRACUNIT;
		else if (player->powers[pw_super])
		{
			if (player->charability == CA_FLOAT)
				player->mo->momz = 28*FRACUNIT; //Obscene jump height anyone?
			else if (player->charability == CA_SLOWFALL)
				player->mo->momz = 37*(FRACUNIT/2); //Less obscene because during super, floating propells oneself upward.
			else // Default super jump momentum.
				player->mo->momz = 13*FRACUNIT;
			// Add a boost for super characters with float/slowfall and multiability.
			if (player->charability2 == CA2_MULTIABILITY &&
				(player->charability == CA_FLOAT || player->charability == CA_SLOWFALL))
				player->mo->momz += 2*FRACUNIT;
		}
		else if (player->charability2 == CA2_MULTIABILITY &&
			(player->charability == CA_DOUBLEJUMP || player->charability == CA_FLOAT || player->charability == CA_SLOWFALL))
		{
			// Multiability exceptions, since some abilities cannot effectively use it and need a boost.
			if (player->charability == CA_DOUBLEJUMP)
				player->mo->momz = 23*(FRACUNIT/2); // Increased jump height instead of infinite jumps.
			else if (player->charability == CA_FLOAT || player->charability == CA_SLOWFALL)
				player->mo->momz = 12*FRACUNIT; // Increased jump height due to ineffective repeat.
		}
		else
			player->mo->momz = 39*(FRACUNIT/4); // Default jump momentum.
		// Reduce player momz by 58.5% when underwater.
		if (player->mo->eflags & MFE_UNDERWATER)
		{
			player->mo->momz = FixedMul(player->mo->momz, FixedDiv(117*FRACUNIT, 200*FRACUNIT));
		}
		// Quicksand bitshift reduction.
		if (P_InQuicksand(player->mo))
			player->mo->momz = player->mo->momz>>1;
		player->jumping = 1;
	}
	factor = player->jumpfactor;
	if (twodlevel || (player->mo->flags2 & MF2_TWOD))
		factor += player->jumpfactor / 10;
	P_SetObjectMomZ(player->mo, FixedDiv(factor*player->mo->momz,100*FRACUNIT), false); // Custom height
	// set just an eensy above the ground
	if (player->mo->eflags & MFE_VERTICALFLIP)
	{
		player->mo->z = player->mo->z + (P_GetPlayerHeight(player) - P_GetPlayerSpinHeight(player));
		player->mo->z--;
	}
	else
		player->mo->z++;
	player->mo->z += player->mo->pmomz; // Solves problem of 'hitting around again after jumping on a moving platform'.
	if (!(player->pflags & PF_SPINNING))
		P_ResetScore(player);
	if (player->pflags & PF_MINECART)
	{
		player->pflags &= ~PF_MINECART;
		P_SetTarget(&player->mo->tracer, NULL);
	}
	player->pflags |= PF_JUMPED;
	if (soundandstate)
	{
		if (!player->spectator)
			S_StartSound(player->mo, sfx_jump); // Play jump sound!
		if (!(player->charability2 == CA2_SPINDASH))
			P_SetPlayerMobjState(player->mo, S_PLAY_PLG1);
		else
			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
	}
} |  | 
P_DoJumpStuff
CA_THOK / CA_HOMINGTHOK:
| Thokking Speed | 
| Abilty | Regular | Underwater | SRB1 Mode | SRB1 Mode + Underwater | 
| CA_THOK | actionspd | actionspd/2 | actionspd/2 | actionspd/4 | 
| CA_HOMINGTHOK | actionspd/3 | actionspd/6 | actionspd/6 | actionspd/12 | 
CA_GLIDEANDCLIMB:
| Gliding Speed | 
|  | 100% Scale (Normal) | 75% Scale | 50% Scale | 25% Scale | 200% Scale | 300% Scale | x% Scale | 
| Normal form | actionspd | actionspd*(75/100) =actionspd*0.75
 | actionspd*(50/100) =actionspd*0.5
 | actionspd*(25/100) =actionspd*0.25
 | actionspd*(200/100) =actionspd*2
 | actionspd*(300/100) =actionspd*3
 | actionspd*(x/100) | 
| Super form | actionspd*2 | actionspd*(75/100)*2 =actionspd*0.75*2
 =actionspd*1.5
 | actionspd*(50/100)*2 =actionspd*0.5*2
 =actionspd*2
 | actionspd*(25/100)*2 =actionspd*0.25*2
 =actionspd*0.5
 | actionspd*(200/100)*2 =actionspd*2*2
 =actionspd*4
 | actionspd*(300/100)*2 =actionspd*3*2
 =actionspd*6
 | actionspd*(x/100)*2 | 
CA_SLOWFALL:
| Z momentum | 
|  | Regular gravity | Reverse gravity | 
| Normal form | - gravity*4 | gravity*4 | 
| Super form | gravity*16 | - gravity*16 | 
| 
|  Code - P_DoJumpStuff |  
|  |  
| //
// P_DoJumpStuff
//
// Handles player jumping
//
static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{
	if (player->pflags & PF_STASIS || (player->powers[pw_nocontrol] && player->powers[pw_nocontrol] < 65536))
		return;
	if (cmd->buttons & BT_JUMP && !(player->pflags & PF_JUMPDOWN) && !player->exiting && !(!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]))
	{
		// can't jump while in air, can't jump while jumping
		if (onground || player->climbing || (player->pflags & PF_CARRIED) || (player->pflags & PF_ITEMHANG) || (player->pflags & PF_ROPEHANG) || (player->pflags & PF_MINECART))
		{
			P_DoJump(player, true);
			player->secondjump = 0;
		}
		else if ((player->pflags & PF_MACESPIN) && player->mo->tracer)
		{
			player->pflags &= ~PF_MACESPIN;
			player->powers[pw_flashing] = TICRATE/2;
		}
		else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag)))
		{
			switch (player->charability)
			{
				case CA_THOK:
				case CA_HOMINGTHOK:
					// Now it's Sonic's abilities turn!
					if (player->pflags & PF_JUMPED)
					{
						// If you can turn super and aren't already,
						// and you don't have a shield, do it!
						if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super]
							&& !player->powers[pw_jumpshield] && !player->powers[pw_forceshield]
							&& !player->powers[pw_watershield] && !player->powers[pw_ringshield]
							&& !player->powers[pw_bombshield] && !player->powers[pw_invulnerability]
							&& !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels
							&& ((player->skin == 0) || ALL7EMERALDS(player->powers[pw_emeralds])))
						{
							P_DoSuperTransformation(player, false);
						}
						else // Otherwise, THOK!
						{
							if (!(player->pflags & PF_THOKKED) || (player->charability2 == CA2_MULTIABILITY))
							{
								mobj_t *item;
								// Catapult the player
								if ((player->mo->eflags & MFE_UNDERWATER))
									P_InstaThrust(player->mo, player->mo->angle, (player->actionspd<<FRACBITS)/2);
								else
									P_InstaThrust(player->mo, player->mo->angle, player->actionspd<<FRACBITS);
								if (maptol & TOL_SRB1)
								{
									player->mo->momx /= 2;
									player->mo->momy /= 2;
								}
								else if (player->charability == CA_HOMINGTHOK)
								{
									player->mo->momx /= 3;
									player->mo->momy /= 3;
								}
								if (player->mo->info->attacksound && !player->spectator)
									S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound
								item = P_SpawnThokMobj(player);
								if (item && (player->charflags & SF_GHOSTTHOKITEM))
								{
									P_SpawnGhostMobj(item);
									P_SetMobjState(item, S_DISS);
								}
								if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED))
								{
									if (P_LookForEnemies(player))
									{
										if (player->mo->tracer)
											player->homing = 3*TICRATE;
									}
								}
								player->pflags &= ~PF_SPINNING;
								player->pflags &= ~PF_STARTDASH;
								player->pflags |= PF_THOKKED;
							}
						}
					}
					else if (player->powers[pw_jumpshield] && !player->powers[pw_super])
						P_DoJumpShield(player);
					break;
				case CA_FLY:
				case CA_SWIM: // Swim
					// If you can turn super and aren't already,
					// and you don't have a shield, do it!
					if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super] && !player->powers[pw_tailsfly]
						&& !player->powers[pw_jumpshield] && !player->powers[pw_forceshield]
						&& !player->powers[pw_watershield] && !player->powers[pw_ringshield]
						&& !player->powers[pw_bombshield] && !player->powers[pw_invulnerability]
						&& !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels
						&& player->pflags & PF_JUMPED
						&& ((player->skin == 0) || ALL7EMERALDS(player->powers[pw_emeralds])))
					{
						P_DoSuperTransformation(player, false);
					}
					// If currently in the air from a jump, and you pressed the
					// button again and have the ability to fly, do so!
					else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly]) && (player->pflags & PF_JUMPED) && !(player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)))
					{
						P_SetPlayerMobjState(player->mo, S_PLAY_ABL1); // Change to the flying animation
						player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer
						player->pflags &= ~PF_JUMPED;
						player->pflags &= ~PF_SPINNING;
						player->pflags &= ~PF_STARTDASH;
						player->pflags |= PF_THOKKED;
					}
					// If currently flying, give an ascend boost.
					else if (player->powers[pw_tailsfly] && !(player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)))
					{
						if (!player->fly1)
							player->fly1 = 20;
						else
							player->fly1 = 2;
						if (player->charability == CA_SWIM)
							player->fly1 /= 2;
					}
					else if (player->powers[pw_jumpshield] && !player->powers[pw_super])
						P_DoJumpShield(player);
					break;
				case CA_GLIDEANDCLIMB:
					// Now Knuckles-type abilities are checked.
					// If you can turn super and aren't already,
					// and you don't have a shield, do it!
					if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super]
						&& !player->powers[pw_jumpshield] && !player->powers[pw_forceshield]
						&& !player->powers[pw_watershield] && !player->powers[pw_ringshield]
						&& !player->powers[pw_bombshield] && !player->powers[pw_invulnerability]
						&& !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels
						&& player->pflags & PF_JUMPED
						&& ((player->skin == 0) || ALL7EMERALDS(player->powers[pw_emeralds])))
					{
						P_DoSuperTransformation(player, false);
					}
					else if ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY))
					{
						//INT32 glidespeed = player->actionspd;
						player->pflags |= PF_GLIDING;
						player->pflags |= PF_THOKKED;
						player->glidetime = 0;
						if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
						{
							// Glide at double speed while super.
							player->actionspd = atoi(skins[player->skin].actionspd)*player->mo->scale/100 * 2;
							player->pflags &= ~PF_THOKKED;
						}
						else
							player->actionspd = atoi(skins[player->skin].actionspd)*player->mo->scale/100;
						P_SetPlayerMobjState(player->mo, S_PLAY_ABL1);
						P_InstaThrust(player->mo, player->mo->angle, (player->actionspd<<FRACBITS)/NEWTICRATERATIO);
						player->pflags &= ~PF_SPINNING;
						player->pflags &= ~PF_STARTDASH;
					}
					else if (player->powers[pw_jumpshield] && !player->powers[pw_super])
						P_DoJumpShield(player);
					break;
				case CA_DOUBLEJUMP: // Double-Jump
					if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super]
						&& !player->powers[pw_jumpshield] && !player->powers[pw_forceshield]
						&& !player->powers[pw_watershield] && !player->powers[pw_ringshield]
						&& !player->powers[pw_bombshield] && !player->powers[pw_invulnerability]
						&& !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels
						&& player->pflags & PF_JUMPED
						&& ((player->skin == 0) || ALL7EMERALDS(player->powers[pw_emeralds])))
					{
						P_DoSuperTransformation(player, false);
					}
					else if ((player->pflags & PF_JUMPED) && !player->secondjump)
					{
						player->pflags &= ~PF_JUMPED;
						P_DoJump(player, true);
						// Allow infinite double jumping if super.
						if (!player->powers[pw_super])
							player->secondjump = 1;
					}
					else if (player->powers[pw_jumpshield] && !player->powers[pw_super])
						P_DoJumpShield(player);
					break;
				case CA_FLOAT: // Float
				case CA_SLOWFALL: // Slow descent hover
					if ((player->pflags & PF_SUPERREADY) && !player->powers[pw_super]
						&& !player->powers[pw_jumpshield] && !player->powers[pw_forceshield]
						&& !player->powers[pw_watershield] && !player->powers[pw_ringshield]
						&& !player->powers[pw_bombshield] && !player->powers[pw_invulnerability]
						&& !(maptol & TOL_NIGHTS) // don't turn 'regular super' in nights levels
						&& player->pflags & PF_JUMPED
						&& ((player->skin == 0) || ALL7EMERALDS(player->powers[pw_emeralds])))
					{
						P_DoSuperTransformation(player, false);
					}
					else if ((player->pflags & PF_JUMPED) && !player->secondjump)
					{
						player->secondjump = 1;
					}
					else if (player->powers[pw_jumpshield] && !player->powers[pw_super])
						P_DoJumpShield(player);
					break;
				default:
					break;
			}
		}
	}
	player->pflags |= PF_JUMPDOWN;
	if (!(cmd->buttons & BT_JUMP))// If not pressing the jump button
	{
		player->pflags &= ~PF_JUMPDOWN;
		// Repeat abilities, but not double jump!
		if ((player->charability2 == CA2_MULTIABILITY && player->charability != CA_DOUBLEJUMP)
			|| (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])))
			player->secondjump = 0;
		else if ((player->charability == CA_FLOAT) && player->secondjump == 1)
			player->secondjump = 2;
	}
	if ((gametype != GT_CTF) || (!player->gotflag))
	{
		if (player->secondjump == 1 && (cmd->buttons & BT_JUMP))
		{
			if (player->charability == CA_FLOAT)
				player->mo->momz = 0;
			else if (player->charability == CA_SLOWFALL)
			{
				if (!(player->mo->eflags & MFE_VERTICALFLIP))
				{
					if (!player->powers[pw_super] && player->mo->momz < -gravity*4)
						player->mo->momz = -gravity*4;
					else if (player->powers[pw_super] && player->mo->momz < gravity*16)
						player->mo->momz = gravity*16; //Float upward 4x as fast while super.
				}
				else
				{
					if (!player->powers[pw_super] && player->mo->momz > gravity*4)
						player->mo->momz = gravity*4;
					else if (player->powers[pw_super] && player->mo->momz > -gravity*16)
						player->mo->momz = -gravity*16; //Float "upward" 4x as fast while super.
				}
			}
			player->pflags &= ~PF_SPINNING;
		}
	}
	// If letting go of the jump button while still on ascent, cut the jump height.
	if (!(player->pflags & PF_JUMPDOWN) && (player->pflags & PF_JUMPED) && ((player->mo->eflags & MFE_VERTICALFLIP && player->mo->momz < 0) || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->momz > 0)) && player->jumping == 1)
	{
		player->mo->momz >>= 1;
		player->jumping = 0;
	}
} |  | 
P_2dMovement
| 
|  Code - P_2dMovement |  
|  |  
| // Control scheme for 2d levels.
static void P_2dMovement(player_t *player)
{
	ticcmd_t *cmd;
	INT32 topspeed, acceleration, thrustfactor;
	fixed_t movepushforward = 0;
	angle_t movepushangle = 0;
	fixed_t normalspd = player->normalspeed;
	cmd = &player->cmd;
	if (player->exiting
		|| (player->pflags & PF_STASIS)
		|| (player->powers[pw_nocontrol]) || (player->powers[pw_ingoop]))
	{
		cmd->forwardmove = cmd->sidemove = 0;
		if (player->pflags & PF_GLIDING)
			player->pflags &= ~PF_GLIDING;
		if (player->pflags & PF_SPINNING && !player->exiting)
		{
			player->pflags &= ~PF_SPINNING;
			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
		}
	}
	// cmomx/cmomy stands for the conveyor belt speed.
	if (player->onconveyor == 2) // Wind/Current
	{
		//if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom)
		if (!(player->mo->eflags & MFE_UNDERWATER) && !(player->mo->eflags & MFE_TOUCHWATER))
			player->cmomx = player->cmomy = 0;
	}
	else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt
		player->cmomx = player->cmomy = 0;
	else if (player->onconveyor != 2 && player->onconveyor != 4)
		player->cmomx = player->cmomy = 0;
	player->rmomx = player->mo->momx - player->cmomx;
	player->rmomy = player->mo->momy - player->cmomy;
	// Calculates player's speed based on distance-of-a-line formula
	player->speed = abs(player->rmomx)>>FRACBITS;
	if (player->pflags & PF_GLIDING)
	{
		// Angle fix.
		if (player->mo->angle < ANGLE_180 && player->mo->angle > ANGLE_90)
			player->mo->angle = ANGLE_180;
		else if (player->mo->angle < ANGLE_90 && player->mo->angle > 0)
			player->mo->angle = 0;
		if (cmd->sidemove > 0 && player->mo->angle != 0 && player->mo->angle >= ANGLE_180)
			player->mo->angle += (640/NEWTICRATERATIO)<<FRACBITS;
		else if (cmd->sidemove < 0 && player->mo->angle != ANGLE_180 && (player->mo->angle > ANGLE_180 || player->mo->angle == 0))
			player->mo->angle -= (640/NEWTICRATERATIO)<<FRACBITS;
		else if (cmd->sidemove == 0)
		{
			if (player->mo->angle >= ANGLE_270)
				player->mo->angle += (640/NEWTICRATERATIO)<<FRACBITS;
			else if (player->mo->angle < ANGLE_270 && player->mo->angle > ANGLE_180)
				player->mo->angle -= (640/NEWTICRATERATIO)<<FRACBITS;
		}
	}
	else if (cmd->sidemove && !(player->climbing) && !(!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]))
	{
		if (cmd->sidemove > 0)
			player->mo->angle = 0;
		else if (cmd->sidemove < 0)
			player->mo->angle = ANGLE_180;
	}
	if (player == &players[consoleplayer])
		localangle = player->mo->angle;
	else if (splitscreen && player == &players[secondarydisplayplayer])
		localangle2 = player->mo->angle;
	if (player->pflags & PF_GLIDING)
		movepushangle = player->mo->angle;
	else
	{
		if (cmd->sidemove > 0)
			movepushangle = 0;
		else if (cmd->sidemove < 0)
			movepushangle = ANGLE_180;
		else
			movepushangle = player->mo->angle;
	}
	// Do not let the player control movement if not onground.
	onground = P_IsObjectOnGround(player->mo);
	player->aiming = cmd->aiming<<FRACBITS;
	// Set the player speeds.
	if (maptol & TOL_SRB1)
		normalspd = (normalspd / 3) * 2;
	if (player->powers[pw_super] || player->powers[pw_sneakers])
	{
		thrustfactor = player->thrustfactor*2;
		acceleration = player->accelstart/4 + player->speed*(player->acceleration/4);
		if (player->powers[pw_tailsfly])
			topspeed = normalspd;
		else if (player->mo->eflags & MFE_UNDERWATER && !(player->pflags & PF_SLIDING))
		{
			topspeed = normalspd;
			acceleration = (acceleration * 2) / 3;
		}
		else
			topspeed = normalspd * 2 > 50 ? 50 : normalspd * 2;
	}
	else
	{
		thrustfactor = player->thrustfactor;
		acceleration = player->accelstart + player->speed*player->acceleration;
		if (player->powers[pw_tailsfly])
		{
			topspeed = normalspd/2;
		}
		else if (player->mo->eflags & MFE_UNDERWATER && !(player->pflags & PF_SLIDING))
		{
			topspeed = normalspd/2;
			acceleration = (acceleration * 2) / 3;
		}
		else
		{
			topspeed = normalspd;
		}
	}
//////////////////////////////////////
	if (player->climbing == 1)
	{
		P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT,10*FRACUNIT), false);
		if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
			player->mo->momz *= 2;
		player->mo->momx = 0;
	}
	if (cmd->sidemove != 0 && !(player->climbing || (player->pflags & PF_GLIDING) || player->exiting
		|| (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]
		&& !onground)))
	{
		if (player->powers[pw_sneakers] || player->powers[pw_super]) // do you have super sneakers?
			movepushforward = abs(cmd->sidemove) * ((thrustfactor*2)*acceleration);
		else // if not, then run normally
			movepushforward = abs(cmd->sidemove) * (thrustfactor*acceleration);
		// allow very small movement while in air for gameplay
		if (!onground)
			movepushforward >>= 1; // Proper air movement
		// Allow a bit of movement while spinning
		if (player->pflags & PF_SPINNING)
		{
			if (!(player->pflags & PF_STARTDASH))
				movepushforward = movepushforward/48;
			else
				movepushforward = 0;
		}
		if (((player->rmomx>>FRACBITS) < topspeed) && (cmd->sidemove > 0)) // Sonic's Speed
			P_Thrust(player->mo, movepushangle, movepushforward);
		else if (((player->rmomx>>FRACBITS) > -topspeed) && (cmd->sidemove < 0))
			P_Thrust(player->mo, movepushangle, movepushforward);
	}
} |  | 
P_3dMovement
| 
|  Code - P_3dMovement |  
|  |  
| static void P_3dMovement(player_t *player)
{
	ticcmd_t *cmd;
	angle_t movepushangle, movepushsideangle; // Analog
	INT32 topspeed, acceleration, thrustfactor;
	fixed_t movepushforward = 0, movepushside = 0;
	INT32 mforward = 0, mbackward = 0;
	camera_t *thiscam;
	fixed_t normalspd = player->normalspeed;
	if (splitscreen && player == &players[secondarydisplayplayer])
		thiscam = &camera2;
	else
		thiscam = &camera;
	cmd = &player->cmd;
	if (player->exiting
		|| (player->pflags & PF_STASIS)
		|| (player->powers[pw_nocontrol]) || (player->powers[pw_ingoop]))
	{
		cmd->forwardmove = cmd->sidemove = 0;
		if (player->pflags & PF_GLIDING)
			player->pflags &= ~PF_GLIDING;
		if (player->pflags & PF_SPINNING && !player->exiting)
		{
			player->pflags &= ~PF_SPINNING;
			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
		}
	}
	if (!netgame && ((player == &players[consoleplayer] && cv_analog.value) || (splitscreen && player == &players[secondarydisplayplayer] && cv_analog2.value)))
	{
		movepushangle = thiscam->angle;
		movepushsideangle = thiscam->angle-ANGLE_90;
	}
	else
	{
		movepushangle = player->mo->angle;
		movepushsideangle = player->mo->angle-ANGLE_90;
	}
	// cmomx/cmomy stands for the conveyor belt speed.
	if (player->onconveyor == 2) // Wind/Current
	{
		//if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom)
		if (!(player->mo->eflags & MFE_UNDERWATER) && !(player->mo->eflags & MFE_TOUCHWATER))
			player->cmomx = player->cmomy = 0;
	}
	else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt
		player->cmomx = player->cmomy = 0;
	else if (player->onconveyor != 2 && player->onconveyor != 4)
		player->cmomx = player->cmomy = 0;
	player->rmomx = player->mo->momx - player->cmomx;
	player->rmomy = player->mo->momy - player->cmomy;
	// Calculates player's speed based on distance-of-a-line formula
	player->speed = P_AproxDistance(player->rmomx, player->rmomy)>>FRACBITS;
	// This determines if the player is facing the direction they are travelling or not.
	// Didn't your teacher say to pay attention in Geometry/Trigonometry class? ;)
	// forward
	if ((player->rmomx > 0 && player->rmomy > 0) && (/*player->mo->angle >= 0 &&*/ player->mo->angle < ANGLE_90)) // Quadrant 1
		mforward = 1;
	else if ((player->rmomx < 0 && player->rmomy > 0) && (player->mo->angle >= ANGLE_90 && player->mo->angle < ANGLE_180)) // Quadrant 2
		mforward = 1;
	else if ((player->rmomx < 0 && player->rmomy < 0) && (player->mo->angle >= ANGLE_180 && player->mo->angle < ANGLE_270)) // Quadrant 3
		mforward = 1;
	else if ((player->rmomx > 0 && player->rmomy < 0) && ((player->mo->angle >= ANGLE_270 /*&& (player->mo->angle <= ANGLE_MAX)*/) || (/*player->mo->angle >= 0 &&*/ player->mo->angle <= ANGLE_45))) // Quadrant 4
		mforward = 1;
	else if (player->rmomx > 0 && ((player->mo->angle >= ANGLE_315 /*&& player->mo->angle <= ANGLE_MAX*/)))
		mforward = 1;
	else if (player->rmomx < 0 && (player->mo->angle >= ANGLE_135 && player->mo->angle <= ANGLE_225))
		mforward = 1;
	else if (player->rmomy > 0 && (player->mo->angle >= ANGLE_45 && player->mo->angle <= ANGLE_135))
		mforward = 1;
	else if (player->rmomy < 0 && (player->mo->angle >= ANGLE_225 && player->mo->angle <= ANGLE_315))
		mforward = 1;
	else
		mforward = 0;
	// backward
	if ((player->rmomx > 0 && player->rmomy > 0) && (player->mo->angle >= ANGLE_180 && player->mo->angle < ANGLE_270)) // Quadrant 3
		mbackward = 1;
	else if ((player->rmomx < 0 && player->rmomy > 0) && (player->mo->angle >= ANGLE_270 /*&& (player->mo->angle <= ANGLE_MAX)*/)) // Quadrant 4
		mbackward = 1;
	else if ((player->rmomx < 0 && player->rmomy < 0) && (/*player->mo->angle >= 0 &&*/ player->mo->angle < ANGLE_90)) // Quadrant 1
		mbackward = 1;
	else if ((player->rmomx > 0 && player->rmomy < 0) && (player->mo->angle >= ANGLE_90 && player->mo->angle < ANGLE_180)) // Quadrant 2
		mbackward = 1;
	else if (player->rmomx < 0 && ((player->mo->angle >= ANGLE_315 /*&& player->mo->angle <= ANGLE_MAX*/) || (/*player->mo->angle >= 0 &&*/ player->mo->angle <= ANGLE_45)))
		mbackward = 1;
	else if (player->rmomx > 0 && (player->mo->angle >= ANGLE_135 && player->mo->angle <= ANGLE_225))
		mbackward = 1;
	else if (player->rmomy < 0 && (player->mo->angle >= ANGLE_45 && player->mo->angle <= ANGLE_135))
		mbackward = 1;
	else if (player->rmomy > 0 && (player->mo->angle >= ANGLE_225 && player->mo->angle <= ANGLE_315))
		mbackward = 1;
	else // Put in 'or' checks here!
		mbackward = 0;
	// When sliding, don't allow forward/back
	if (player->pflags & PF_SLIDING)
		cmd->forwardmove = 0;
	// Do not let the player control movement if not onground.
	onground = P_IsObjectOnGround(player->mo);
	player->aiming = cmd->aiming<<FRACBITS;
	// Set the player speeds.
	if (maptol & TOL_SRB1)
		normalspd = (normalspd / 3) * 2;
	if (player->powers[pw_super] || player->powers[pw_sneakers])
	{
		thrustfactor = player->thrustfactor*2;
		acceleration = player->accelstart/4 + player->speed*(player->acceleration/4);
		if (player->powers[pw_tailsfly])
			topspeed = normalspd;
		else if (player->mo->eflags & MFE_UNDERWATER && !(player->pflags & PF_SLIDING))
		{
			topspeed = normalspd;
			acceleration = (acceleration * 2) / 3;
		}
		else
			topspeed = normalspd * 2 > 50 ? 50 : normalspd * 2;
	}
	else
	{
		thrustfactor = player->thrustfactor;
		acceleration = player->accelstart + player->speed*player->acceleration;
		if (player->powers[pw_tailsfly])
			topspeed = normalspd/2;
		else if (player->mo->eflags & MFE_UNDERWATER && !(player->pflags & PF_SLIDING))
		{
			topspeed = normalspd/2;
			acceleration = (acceleration * 2) / 3;
		}
		else
			topspeed = normalspd;
	}
	// Better maneuverability while flying
	if(player->powers[pw_tailsfly])
	{
		thrustfactor = player->thrustfactor*2;
		acceleration = player->accelstart + player->speed*player->acceleration;
	}
	if ((netgame || (player == &players[consoleplayer] && !cv_analog.value)
		|| (splitscreen && player == &players[secondarydisplayplayer] && !cv_analog2.value))
		&& cmd->forwardmove != 0 && !((player->pflags & PF_GLIDING) || player->exiting
		|| (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]
		&& !onground)))
	{
		if (player->climbing)
		{
			P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT,10*FRACUNIT), false);
			if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
				player->mo->momz *= 2;
		}
		else if (player->powers[pw_sneakers] || player->powers[pw_super]) // super sneakers?
			movepushforward = cmd->forwardmove * ((thrustfactor*2)*acceleration);
		else // if not, then run normally
			movepushforward = cmd->forwardmove * (thrustfactor*acceleration);
		// allow very small movement while in air for gameplay
		if (!onground)
			movepushforward >>= 2; // proper air movement
		// Allow a bit of movement while spinning
		if (player->pflags & PF_SPINNING)
		{
			if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0))
				movepushforward = 0;
			else if (!(player->pflags & PF_STARTDASH))
				movepushforward = FixedDiv(movepushforward,16*FRACUNIT);
			else
				movepushforward = 0;
		}
		if ((player->speed < topspeed) && (mforward) && (cmd->forwardmove > 0)) // Sonic's Speed
			P_Thrust(player->mo, movepushangle, movepushforward);
		else if ((mforward) && (cmd->forwardmove < 0))
			P_Thrust(player->mo, movepushangle, movepushforward);
		else if ((player->speed < topspeed) && (mbackward) && (cmd->forwardmove < 0))
			P_Thrust(player->mo, movepushangle, movepushforward);
		else if ((mbackward) && (cmd->forwardmove > 0))
			P_Thrust(player->mo, movepushangle, movepushforward);
		else if (!mforward && !mbackward)
			P_Thrust(player->mo, movepushangle, movepushforward);
	}
	// Analog movement control
	if (!netgame && ((player == &players[consoleplayer] && cv_analog.value)
		|| (splitscreen && player == &players[secondarydisplayplayer]
		&& cv_analog2.value)) && thiscam->chase)
	{
		if (!((player->pflags & PF_GLIDING) || player->exiting || (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate]
			&& player->powers[pw_flashing])))
		{
			angle_t controldirection, controllerdirection, controlplayerdirection;
			fixed_t tempx, tempy;
			angle_t tempangle;
			boolean cforward; // controls pointing forward from the player
			boolean cbackward; // controls pointing backward from the player
			tempx = tempy = 0;
			cforward = cbackward = false;
			// Calculate the angle at which the controls are pointing
			// to figure out the proper mforward and mbackward.
			tempangle = thiscam->angle;
			tempangle >>= ANGLETOFINESHIFT;
			tempx += FixedMul(cmd->forwardmove,FINECOSINE(tempangle));
			tempy += FixedMul(cmd->forwardmove,FINESINE(tempangle));
			tempangle = thiscam->angle-ANGLE_90;
			tempangle >>= ANGLETOFINESHIFT;
			tempx += FixedMul(cmd->sidemove,FINECOSINE(tempangle));
			tempy += FixedMul(cmd->sidemove,FINESINE(tempangle));
			tempx = tempx*FRACUNIT;
			tempy = tempy*FRACUNIT;
			controldirection = controllerdirection =
				R_PointToAngle2(player->mo->x, player->mo->y, player->mo->x + tempx,
					player->mo->y + tempy);
			controlplayerdirection = player->mo->angle;
			if (controlplayerdirection < ANGLE_90)
			{
				controlplayerdirection += ANGLE_90;
				controllerdirection += ANGLE_90;
			}
			else if (controlplayerdirection >= ANGLE_270)
			{
				controlplayerdirection -= ANGLE_90;
				controllerdirection -= ANGLE_90;
			}
			// Controls pointing backwards from player
			if (controllerdirection > controlplayerdirection + ANGLE_90
				&& controllerdirection < controlplayerdirection - ANGLE_90)
			{
				cbackward = true;
			}
			else // Controls pointing in player's general direction
				cforward = true;
			if (player->climbing)
			{
				fixed_t value = 10*FRACUNIT;
				// Thrust in the direction of the controls
				P_SetObjectMomZ(player->mo, FixedDiv(cmd->forwardmove*FRACUNIT,10*FRACUNIT), false);
				if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
				{
					player->mo->momz *= 2;
					value /= 2;
				}
				P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FixedDiv(cmd->sidemove*FRACUNIT,value));
			}
			else if (player->powers[pw_sneakers] || player->powers[pw_super]) // super sneakers?
				movepushforward = FixedMul(FixedHypot(cmd->sidemove*FRACUNIT, cmd->forwardmove*FRACUNIT), ((thrustfactor*2)*acceleration));
			else // if not, then run normally
				movepushforward = FixedMul(FixedHypot(cmd->sidemove*FRACUNIT, cmd->forwardmove*FRACUNIT), ((thrustfactor*1)*acceleration));
			// allow very small movement while in air for gameplay
			if (!onground)
				movepushforward >>= 2; // proper air movement
			// Allow a bit of movement while spinning
			if (player->pflags & PF_SPINNING)
			{
				// Stupid little movement prohibitor hack
				// that REALLY shouldn't belong in analog code.
				if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0))
					movepushforward = 0;
				else if (!(player->pflags & PF_STARTDASH))
					movepushforward = FixedDiv(movepushforward, 16*FRACUNIT);
				else
					movepushforward = 0;
			}
			movepushsideangle = controldirection;
			if (player->speed < topspeed)
				P_Thrust(player->mo, controldirection, movepushforward);
			else if ((mforward) && (cbackward))
				P_Thrust(player->mo, controldirection, movepushforward);
			else if ((mbackward) && (cforward))
				P_Thrust(player->mo, controldirection, movepushforward);
		}
	}
	else if (netgame || (player == &players[consoleplayer] && !cv_analog.value)
		|| (splitscreen && player == &players[secondarydisplayplayer]
		&& !cv_analog2.value))
	{
		if (player->climbing)
		{
			if (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
				P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FIXEDSCALE((cmd->sidemove/5)*FRACUNIT, player->mo->scale));
			else
				P_InstaThrust(player->mo, player->mo->angle-ANGLE_90, FIXEDSCALE((cmd->sidemove/10)*FRACUNIT, player->mo->scale));
			player->mo->momx = FIXEDSCALE(player->mo->momx,player->mo->scale);
			player->mo->momy = FIXEDSCALE(player->mo->momy,player->mo->scale);
		}
		else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !player->climbing && !(!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]))
		{
			boolean mright;
			boolean mleft;
			angle_t sideangle;
			sideangle = player->mo->angle - ANGLE_90;
			// forward
			if ((player->rmomx > 0 && player->rmomy > 0) && (/*sideangle >= 0 &&*/ sideangle < ANGLE_90)) // Quadrant 1
				mright = 1;
			else if ((player->rmomx < 0 && player->rmomy > 0) && (sideangle >= ANGLE_90 && sideangle < ANGLE_180)) // Quadrant 2
				mright = 1;
			else if ((player->rmomx < 0 && player->rmomy < 0) && (sideangle >= ANGLE_180 && sideangle < ANGLE_270)) // Quadrant 3
				mright = 1;
			else if ((player->rmomx > 0 && player->rmomy < 0) && ((sideangle >= ANGLE_270 /*&& (sideangle <= ANGLE_MAX)*/) || (/*sideangle >= 0 &&*/ sideangle <= ANGLE_45))) // Quadrant 4
				mright = 1;
			else if (player->rmomx > 0 && ((sideangle >= ANGLE_315 /*&& sideangle <= ANGLE_MAX*/)))
				mright = 1;
			else if (player->rmomx < 0 && (sideangle >= ANGLE_135 && sideangle <= ANGLE_225))
				mright = 1;
			else if (player->rmomy > 0 && (sideangle >= ANGLE_45 && sideangle <= ANGLE_135))
				mright = 1;
			else if (player->rmomy < 0 && (sideangle >= ANGLE_225 && sideangle <= ANGLE_315))
				mright = 1;
			else
				mright = 0;
			// backward
			if ((player->rmomx > 0 && player->rmomy > 0) && (sideangle >= ANGLE_180 && sideangle < ANGLE_270)) // Quadrant 3
				mleft = 1;
			else if ((player->rmomx < 0 && player->rmomy > 0) && (sideangle >= ANGLE_270 /*&& (sideangle <= ANGLE_MAX)*/)) // Quadrant 4
				mleft = 1;
			else if ((player->rmomx < 0 && player->rmomy < 0) && (/*sideangle >= 0 &&*/ sideangle < ANGLE_90)) // Quadrant 1
				mleft = 1;
			else if ((player->rmomx > 0 && player->rmomy < 0) && (sideangle >= ANGLE_90 && sideangle < ANGLE_180)) // Quadrant 2
				mleft = 1;
			else if (player->rmomx < 0 && ((sideangle >= ANGLE_315 /*&& sideangle <= ANGLE_MAX*/) || (/*sideangle >= 0 &&*/ sideangle <= ANGLE_45)))
				mleft = 1;
			else if (player->rmomx > 0 && (sideangle >= ANGLE_135 && sideangle <= ANGLE_225))
				mleft = 1;
			else if (player->rmomy < 0 && (sideangle >= ANGLE_45 && sideangle <= ANGLE_135))
				mleft = 1;
			else if (player->rmomy > 0 && (sideangle >= ANGLE_225 && sideangle <= ANGLE_315))
				mleft = 1;
			else // Put in 'or' checks here!
				mleft = 0;
			movepushside = cmd->sidemove * (thrustfactor*acceleration);
			if (player->powers[pw_sneakers] || player->powers[pw_super])
				movepushside *= 2;
			if (!onground)
			{
				movepushside >>= 2;
				//Lower speed if over "max" flight speed and greatly reduce movepushslide.
				if (player->powers[pw_tailsfly] && player->speed > topspeed)
				{
					player->speed = topspeed - 1;
					movepushside /= 8;
				}
			}
			// Allow a bit of movement while spinning
			if (player->pflags & PF_SPINNING)
			{
				if (!(player->pflags & PF_STARTDASH))
					movepushside = FixedDiv(movepushside,16*FRACUNIT);
				else
					movepushside = 0;
			}
			// Finally move the player now that his speed/direction has been decided.
			if (player->speed < topspeed)
				P_Thrust(player->mo, movepushsideangle, movepushside);
			else if ((mright) && (cmd->sidemove < 0))
				P_Thrust(player->mo, movepushsideangle, movepushside);
			else if ((mleft) && (cmd->sidemove > 0))
				P_Thrust(player->mo, movepushsideangle, movepushside);
		}
	}
} |  | 
P_ObjectplaceMovement
| 
|  Code - P_ObjectplaceMovement |  
|  |  
| //
// P_ObjectplaceMovement
//
// Control code for Objectplace mode
//
static void P_ObjectplaceMovement(player_t *player)
{
	ticcmd_t *cmd = &player->cmd;
	mobj_t *currentitem;
	if (!player->climbing && (netgame || (player == &players[consoleplayer]
		&& !cv_analog.value) || (splitscreen
		&& player == &players[secondarydisplayplayer] && !cv_analog2.value)
		|| (player->pflags & PF_SPINNING)))
	{
		player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
	}
	ticruned++;
	if (!(cmd->angleturn & TICCMD_RECEIVED))
		ticmiss++;
	if (cmd->buttons & BT_JUMP)
		player->mo->z += FRACUNIT*cv_speed.value;
	else if (cmd->buttons & BT_USE)
		player->mo->z -= FRACUNIT*cv_speed.value;
	if (player->mo->target && player->mo->z > player->mo->ceilingz - player->mo->target->height)
		player->mo->z = player->mo->ceilingz - player->mo->target->height;
	else if (!player->mo->target && player->mo->z > player->mo->ceilingz - player->mo->height)
		player->mo->z = player->mo->ceilingz - player->mo->height;
	if (player->mo->z < player->mo->floorz)
		player->mo->z = player->mo->floorz;
	if (cmd->forwardmove != 0)
	{
		P_Thrust(player->mo, player->mo->angle, cmd->forwardmove*(FRACUNIT/4));
		P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
		player->mo->momx = player->mo->momy = 0;
	}
	if (cmd->sidemove != 0)
	{
		P_Thrust(player->mo, player->mo->angle-ANGLE_90, cmd->sidemove*(FRACUNIT/4));
		P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
		player->mo->momx = player->mo->momy = 0;
	}
	if (cmd->buttons & BT_CAMLEFT && !(player->pflags & PF_SKIDDOWN))
	{
		do
		{
			player->currentthing--;
			if (player->currentthing <= 0)
				player->currentthing = NUMMOBJTYPES-1;
		}while (mobjinfo[player->currentthing].doomednum == -1
			|| player->currentthing == MT_NIGHTSDRONE
			|| mobjinfo[player->currentthing].flags & MF_AMBIENT
			|| mobjinfo[player->currentthing].flags & MF_NOSECTOR
			|| mobjinfo[player->currentthing].flags & MF_BOSS
			|| (states[mobjinfo[player->currentthing].spawnstate].sprite == SPR_DISS && player->currentthing != MT_MINUS));
		CONS_Printf("Current mapthing is %d\n", mobjinfo[player->currentthing].doomednum);
		player->pflags |= PF_SKIDDOWN;
	}
	else if (cmd->buttons & BT_CAMRIGHT && !(player->pflags & PF_JUMPDOWN))
	{
		do
		{
			player->currentthing++;
			if (player->currentthing >= NUMMOBJTYPES)
				player->currentthing = 0;
		}while (mobjinfo[player->currentthing].doomednum == -1
			|| player->currentthing == MT_NIGHTSDRONE
			|| mobjinfo[player->currentthing].flags & MF_AMBIENT
			|| mobjinfo[player->currentthing].flags & MF_NOSECTOR
			|| mobjinfo[player->currentthing].flags & MF_BOSS
			|| (states[mobjinfo[player->currentthing].spawnstate].sprite == SPR_DISS && player->currentthing != MT_MINUS));
		CONS_Printf("Current mapthing is %d\n", mobjinfo[player->currentthing].doomednum);
		player->pflags |= PF_JUMPDOWN;
	}
	// Place an object and add it to the maplist
	if (player->mo->target)
		if (cmd->buttons & BT_ATTACK && !(player->pflags & PF_ATTACKDOWN))
		{
			mapthing_t *mt;
			mapthing_t *oldmapthings;
			mobj_t *newthing;
			INT16 x,y,z = 0;
			UINT8 zshift;
			if (player->mo->target->flags & MF_SPAWNCEILING)
			{
				// Move down from the ceiling
				if (cv_snapto.value)
				{
					if (cv_snapto.value == 1) // Snap to floor
						z = (INT16)((player->mo->subsector->sector->ceilingheight - player->mo->floorz)>>FRACBITS);
					else if (cv_snapto.value == 2) // Snap to ceiling
						z = (INT16)((player->mo->subsector->sector->ceilingheight - player->mo->ceilingz - player->mo->target->height)>>FRACBITS);
					else if (cv_snapto.value == 3) // Snap to middle
						z = (INT16)((player->mo->subsector->sector->ceilingheight - (player->mo->ceilingz - player->mo->floorz)/2 - player->mo->target->height/2)>>FRACBITS);
				}
				else
				{
					if (cv_grid.value)
					{
						INT32 adjust;
						adjust = cv_grid.value - (((player->mo->subsector->sector->ceilingheight -
							player->mo->subsector->sector->floorheight)>>FRACBITS) % cv_grid.value);
						z = (INT16)(((player->mo->subsector->sector->ceilingheight - player->mo->z))>>FRACBITS);
						z = (INT16)(z + (INT16)adjust);
						// round to the nearest cv_grid.value
						z = (INT16)((z + cv_grid.value/2) % cv_grid.value);
						z = (INT16)(z - (INT16)adjust);
					}
					else
						z = (INT16)((player->mo->subsector->sector->ceilingheight - player->mo->z)>>FRACBITS);
				}
			}
			else
			{
				if (cv_snapto.value)
				{
					if (cv_snapto.value == 1) // Snap to floor
						z = (INT16)((player->mo->floorz - player->mo->subsector->sector->floorheight)>>FRACBITS);
					else if (cv_snapto.value == 2) // Snap to ceiling
						z = (INT16)((player->mo->ceilingz - player->mo->target->height - player->mo->subsector->sector->floorheight)>>FRACBITS);
					else if (cv_snapto.value == 3) // Snap to middle
						z = (INT16)((((player->mo->ceilingz - player->mo->floorz)/2)-(player->mo->target->height/2)-player->mo->subsector->sector->floorheight)>>FRACBITS);
				}
				else
				{
					if (cv_grid.value)
					{
						z = (INT16)(((player->mo->subsector->sector->ceilingheight - player->mo->z))>>FRACBITS);
						// round to the nearest cv_grid.value
						z = (INT16)((z + cv_grid.value/2) % cv_grid.value);
					}
					else
						z = (INT16)((player->mo->z - player->mo->subsector->sector->floorheight)>>FRACBITS);
				}
			}
			// Starts have height limitations for some reason.
			if (cv_mapthingnum.value >= 1 && cv_mapthingnum.value <= 99)
			{
				if (z >= (1 << (16-(ZSHIFT+1))))
				{
					CONS_Printf("Sorry, you're too %s to place this object (max: %d %s).\n",
						player->mo->target->flags & MF_SPAWNCEILING ? "low" : "high",
						(1 << (16-(ZSHIFT+1))),
						player->mo->target->flags & MF_SPAWNCEILING ? "below top ceiling" : "above bottom floor");
					return;
				}
				zshift = ZSHIFT+1; // Shift it over 5 bits to make room for the flag info.
			}
			else
			{
				if (z >= (1 << (16-ZSHIFT)))
				{
					CONS_Printf("Sorry, you're too %s to place this object (max: %d %s).\n",
						player->mo->target->flags & MF_SPAWNCEILING ? "low" : "high",
						(1 << (16-ZSHIFT)),
						player->mo->target->flags & MF_SPAWNCEILING ? "below top ceiling" : "above bottom floor");
					return;
				}
				zshift = ZSHIFT;
			}
			z <<= zshift;
			// Currently only the Starpost uses this
			if (player->mo->target->flags & MF_SPECIALFLAGS)
			{
				if (player->mo->target->type == MT_STARPOST)
					z = (INT16)z;
			}
			else
				z = (INT16)(z + (INT16)cv_objflags.value); // Easy/med/hard/ambush/etc.
			oldmapthings = mapthings;
			nummapthings++;
#if 0
			mapthings = M_Memcpy(Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL), oldmapthings, sizeof (mapthing_t)*(nummapthings-1));
			Z_Free(oldmapthings);
#else
			mapthings = Z_Realloc(oldmapthings, nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
#endif
			mt = mapthings + nummapthings-1;
			if (cv_grid.value)
			{
				x = (INT16)(P_GridSnap(player->mo->x)>>FRACBITS);
				y = (INT16)(P_GridSnap(player->mo->y)>>FRACBITS);
			}
			else
			{
				x = (INT16)(player->mo->x>>FRACBITS);
				y = (INT16)(player->mo->y>>FRACBITS);
			}
			mt->x = x;
			mt->y = y;
			mt->angle = (INT16)FixedInt(AngleFixed(player->mo->angle));
			if (cv_mapthingnum.value != 0)
			{
				mt->type = (INT16)cv_mapthingnum.value;
				CONS_Printf("Placed object mapthingum %d, not the one below.\n", mt->type);
			}
			else
				mt->type = (INT16)mobjinfo[player->currentthing].doomednum;
			mt->options = z;
			newthing = P_SpawnMobj(x << FRACBITS, y << FRACBITS, player->mo->target->flags & MF_SPAWNCEILING ? player->mo->subsector->sector->ceilingheight - ((z>>zshift)<<FRACBITS) : player->mo->subsector->sector->floorheight + ((z>>zshift)<<FRACBITS), player->currentthing);
			newthing->angle = player->mo->angle;
			newthing->spawnpoint = mt;
			CONS_Printf("Placed object type %d at %d, %d, %d, %d\n", newthing->info->doomednum, mt->x, mt->y, newthing->z>>FRACBITS, mt->angle);
			player->pflags |= PF_ATTACKDOWN;
		}
	if (cmd->buttons & BT_TAUNT) // Remove any objects near you
	{
		thinker_t *th;
		mobj_t *mo2;
		boolean done = false;
		// scan the thinkers
		for (th = thinkercap.next; th != &thinkercap; th = th->next)
		{
			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
				continue;
			mo2 = (mobj_t *)th;
			if (mo2 == player->mo->target)
				continue;
			if (mo2 == player->mo)
				continue;
			if (P_AproxDistance(P_AproxDistance(mo2->x - player->mo->x, mo2->y - player->mo->y), mo2->z - player->mo->z) < player->mo->radius)
			{
				if (mo2->spawnpoint)
				{
					mapthing_t *mt;
					size_t i;
					P_SetMobjState(mo2, S_DISS);
					mt = mapthings;
					for (i = 0; i < nummapthings; i++, mt++)
					{
						if (done)
							continue;
						if (mt->mobj == mo2) // Found it! Now to delete...
						{
							mapthing_t *oldmapthings;
							mapthing_t *oldmt;
							mapthing_t *newmt;
							size_t z;
							CONS_Printf("Deleting...\n");
							oldmapthings = mapthings;
							nummapthings--;
							mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
							// Gotta rebuild the WHOLE MAPTHING LIST,
							// otherwise it doesn't work!
							oldmt = oldmapthings;
							newmt = mapthings;
							for (z = 0; z < nummapthings+1; z++, oldmt++, newmt++)
							{
								if (oldmt->mobj == mo2)
								{
									CONS_Printf("Deleted.\n");
									newmt--;
									continue;
								}
								newmt->x = oldmt->x;
								newmt->y = oldmt->y;
								newmt->angle = oldmt->angle;
								newmt->type = oldmt->type;
								newmt->options = oldmt->options;
								newmt->z = oldmt->z;
								newmt->mobj = oldmt->mobj;
							}
							Z_Free(oldmapthings);
							done = true;
						}
					}
				}
				else
					CONS_Printf("You cannot delete this item because it doesn't have a mapthing!\n");
			}
			done = false;
		}
	}
	if (!(cmd->buttons & BT_ATTACK))
		player->pflags &= ~PF_ATTACKDOWN;
	if (!(cmd->buttons & BT_CAMLEFT))
		player->pflags &= ~PF_SKIDDOWN;
	if (!(cmd->buttons & BT_CAMRIGHT))
		player->pflags &= ~PF_JUMPDOWN;
	if (!player->mo->target || player->currentthing != player->mo->target->type)
	{
		if (player->mo->target)
			P_RemoveMobj(player->mo->target); // The object has MF_NOTHINK, so S_DISS would never pass.
		currentitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, player->currentthing);
		currentitem->flags |= MF_NOTHINK;
		currentitem->angle = player->mo->angle;
		currentitem->tics = -1;
		P_SetTarget(&player->mo->target, currentitem);
		P_UnsetThingPosition(currentitem);
		currentitem->flags |= MF_NOBLOCKMAP;
		currentitem->flags |= MF_NOCLIP;
		P_SetThingPosition(currentitem);
		currentitem->floorz = player->mo->floorz;
		currentitem->ceilingz = player->mo->ceilingz;
	}
	else if (player->mo->target)
	{
		P_UnsetThingPosition(player->mo->target);
		player->mo->target->x = player->mo->x;
		player->mo->target->y = player->mo->y;
		player->mo->target->z = player->mo->z;
		P_SetThingPosition(player->mo->target);
		player->mo->target->angle = player->mo->angle;
		player->mo->target->floorz = player->mo->floorz;
		player->mo->target->ceilingz = player->mo->ceilingz;
	}
} |  | 
P_NukeEnemies
Range of Armageddon Shield's explosion = dist = 1536 << FRACBITS
- = 1536*FRACUNIT
- = 1536 fracunits
| 
|  Code - P_NukeEnemies |  
|  |  
| //
// P_NukeEnemies
// Looks for something you can hit - Used for bomb shield
//
void P_NukeEnemies(player_t *player)
{
	const fixed_t dist = 1536 << FRACBITS;
	const fixed_t ns = 60 << FRACBITS;
	mobj_t *mo;
	angle_t fa;
	thinker_t *think;
	INT32 i;
	for (i = 0; i < 16; i++)
	{
		fa = (i*(FINEANGLES/16));
		mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK);
		mo->momx = FixedMul(FINESINE(fa),ns)/NEWTICRATERATIO;
		mo->momy = FixedMul(FINECOSINE(fa),ns)/NEWTICRATERATIO;
	}
	for (think = thinkercap.next; think != &thinkercap; think = think->next)
	{
		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
			continue; // not a mobj thinker
		mo = (mobj_t *)think;
		if (!(mo->flags & MF_SHOOTABLE))
			continue;
		if (mo->flags & MF_MONITOR)
			continue; // Monitors cannot be 'nuked'.
		if ((gametype == GT_COOP || gametype == GT_RACE) && mo->type == MT_PLAYER)
			continue; // Don't hurt players in Co-Op!
		if (P_AproxDistance(P_AproxDistance(player->mo->x - mo->x, player->mo->y - mo->y), player->mo->z - mo->z) > dist)
			continue;
		if (mo->flags & MF_BOSS || mo->type == MT_PLAYER) //don't OHKO bosses nor players!
			P_DamageMobj(mo, player->mo, player->mo, 1);
		else
			P_DamageMobj(mo, player->mo, player->mo, 1000);
	}
} |  | 
P_LookForEnemies
Max distance target can be from player = RING_DIST
- = 512*FRACUNIT
- = 512 fracunits
| 
|  Code - P_LookForEnemies |  
|  |  
| //
// P_LookForEnemies
// Looks for something you can hit - Used for homing attack
// Includes monitors and springs!
//
boolean P_LookForEnemies(player_t *player)
{
	mobj_t *mo;
	thinker_t *think;
	mobj_t *closestmo = NULL;
	angle_t an;
	for (think = thinkercap.next; think != &thinkercap; think = think->next)
	{
		if (think->function.acp1 != (actionf_p1)P_MobjThinker)
			continue; // not a mobj thinker
		mo = (mobj_t *)think;
		if (!(mo->flags & MF_ENEMY || mo->flags & MF_BOSS || mo->flags & MF_MONITOR
			|| mo->flags & MF_SPRING))
		{
			continue; // not a valid enemy
		}
		if (mo->health <= 0) // dead
			continue;
		if (mo == player->mo)
			continue;
		if (mo->flags2 & MF2_FRET)
			continue;
		if (mo->type == MT_DETON) // Don't be STUPID, Sonic!
			continue;
		if (mo->flags & MF_MONITOR && mo->state == &states[S_MONITOREXPLOSION5])
			continue;
		if (mo->z > player->mo->z+MAXSTEPMOVE)
			continue; // Don't home upwards!
		if (P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y),
			player->mo->z-mo->z) > RING_DIST)
			continue; // out of range
		if (mo->type == MT_PLAYER) // Don't chase after other players!
			continue;
		if (closestmo && P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y),
			player->mo->z-mo->z) > P_AproxDistance(P_AproxDistance(player->mo->x-closestmo->x,
			player->mo->y-closestmo->y), player->mo->z-closestmo->z))
			continue;
		an = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - player->mo->angle;
		if (an > ANGLE_90 && an < ANGLE_270)
			continue; // behind back
		player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y);
		if (!P_CheckSight(player->mo, mo))
			continue; // out of sight
		closestmo = mo;
	}
	if (closestmo)
	{
		// Found a target monster
		P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, closestmo));
		return true;
	}
	return false;
} |  | 
P_HomingAttack
const fixed_t ns = source->player->actionspd * FRACUNIT;
		source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), FixedDiv(ns,3*FRACUNIT/2));
		source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), FixedDiv(ns,3*FRACUNIT/2));
		source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), FixedDiv(ns,3*FRACUNIT/2));
Speed a player with CA_HOMINGTHOK will home to its target:
- = Distance from target * (actionspd/1.5)
| 
|  Code - P_HomingAttack |  
|  |  
| void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
{
	fixed_t dist;
	if (!enemy)
		return;
	if (!(enemy->health))
		return;
	// change angle
	source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y);
	if (source->player)
	{
		if (source->player == &players[consoleplayer])
			localangle = source->angle;
		else if (splitscreen && source->player == &players[secondarydisplayplayer])
			localangle2 = source->angle;
	}
	// change slope
	dist = P_AproxDistance(P_AproxDistance(enemy->x - source->x, enemy->y - source->y),
		enemy->z - source->z);
	if (dist < 1)
		dist = 1;
	if (source->type == MT_DETON && enemy->player) // For Deton Chase
	{
		fixed_t ns = FixedDiv(enemy->player->normalspeed*FRACUNIT, FixedDiv(20*FRACUNIT,17*FRACUNIT));
		source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
		source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
		source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns);
	}
	else if (source->type != MT_PLAYER)
	{
		if (source->threshold == 32000)
		{
			fixed_t ns = source->info->speed/2;
			source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
			source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
			source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns);
		}
		else
		{
			source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), source->info->speed);
			source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), source->info->speed);
			source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), source->info->speed);
		}
	}
	else if (source->player)
	{
		const fixed_t ns = source->player->actionspd * FRACUNIT;
		source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), FixedDiv(ns,3*FRACUNIT/2));
		source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), FixedDiv(ns,3*FRACUNIT/2));
		source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), FixedDiv(ns,3*FRACUNIT/2));
	}
} |  | 
sinkspeed = Speed the player sinks into the quicksand
friction = Multiplied by the player's current momx/momy to set the "sludginess" of the player's movement
sinkspeed = abs(rover->master->v1->x - rover->master->v2->x)>>1;
- sinkspeed= Linedef X distance/2
 
- sinkspeed= FixedDiv(- sinkspeed,- TICRATE*- FRACUNIT);- = sinkspeed/(35*65536)
- = sinkspeed/2293760
 
 
sinkspeed = (Linedef X distance/2)/2293760
- sinkspeed= Linedef X distance/4587520
- sinkspeed= Linedef X distance/(1 fracunit/70 tics)
 
friction = abs(rover->master->v1->y - rover->master->v2->y)>>6
- friction= Linedef Y distance/64
 
| Linedef X distance (fracunits) | sinkspeed | 
| 0 | 0 | 
| 1 | 1/4587520 = 1 fracunit/70 tics
 | 
| 2 | 2/4587520 = 2 fracunits/70 tics
 = 1 fracunit/35 tics
 | 
| 7 | 7/4587520 = 0.00000152587890625
 = 7 fracunits/70 tics
 = 1 fracunit/10 tics
 | 
| 35 | 35/4587520 = 0.00000762939453125
 = 35 fracunits/70 tics
 = 1 fracunit/2 tics
 | 
| 70 | 70/4587520 = 0.0000152587890625
 = 70 fracunits/70 tics
 = 1 fracunit/1 tic
 | 
| 140 | 140/4587520 = 0.000030517578125
 = 140 fracunits/70 tics
 = 1 fracunit/0.5 tics
 | 
| Linedef Y distance (fracunits) | friction | 
| 0 | 0 = 0% of Player's speed
 | 
| 1 | 1/64 = 0.015625
 = 1.5625% of Player's speed
 | 
| 2 | 2/64 = 1/32
 = 0.03125
 = 3.125% of Player's speed
 | 
| 16 | 16/64 = 1/4
 = 0.25
 = 25% of Player's speed
 | 
| 32 | 32/64 = 1/2
 = 0.5
 = 50% of Player's speed
 | 
| 48 | 48/64 = 3/4
 = 0.75
 = 75% of Player's speed
 | 
| 64 | 64/64 = 1
 = 100% of Player's speed
 | 
| 128 | 128/64 = 2
 = 200% of Player's speed
 | 
MAXCAMERADIST = 140*FRACUNIT
- = 140 fracunits (Max distance the camera can be in front of the player, in 2D mode)
 
r_things.h
MAXSPRITELUMPS = 8192
MAXVISSPRITES = 2048
SKINNAMESIZE = 16
DEFAULTSKIN = "sonic\0\0\0\0\0\0\0\0\0\0"
s_sound.c/s_sound.h
S_MAX_VOLUME = 127
S_CLIPPING_DIST = 1536*0x10000
- = 1536*FRACUNIT
- = 1536 fracunits (when to clip out sounds)
 
S_CLOSE_DIST = 160*0x10000
- = 160*FRACUNIT
- = 160 fracunits (Distance to origin when sounds should be maxed out)
 
S_ATTENUATOR = ((S_CLIPPING_DIST-S_CLOSE_DIST)>>(FRACBITS+4))
- = ((1536*FRACUNIT-160*FRACUNIT)>>(20))
- = (1376*FRACUNIT)/ 2^20
- = 90177536/1048576
- = 86
 
NORM_VOLUME = snd_MaxVolume
NORM_PITCH = 128
NORM_PRIORITY = 64
NORM_SEP = 128
S_PITCH_PERTURB = 1
S_STEREO_SWING = 96*0x10000
- = 96*FRACUNIT
- = 96 fracunits
 
SURROUND_SEP = -128
S_IFRACVOL = 30
Mario Mode Sounds
The following sounds change in Mario mode:
| Replaced Sound(s) | Mario Mode sound | 
| 6 - sfx_altow17 -
 sfx_altow28 -
 sfx_altow39 -
 sfx_altow4 | 100 - sfx_mario8 | 
| 228 - sfx_thok | 99 - sfx_mario7 | 
| 119 - sfx_pop | 97 - sfx_mario5 | 
| 84 - sfx_jump | 98 - sfx_mario6 | 
| 208 - sfx_shield | 95 - sfx_mario3 | 
| 83 - sfx_itemup | 96 - sfx_mario4 | 
| 230 - sfx_tink | 93 - sfx_mario1 | 
| 41 - sfx_cgot | 101 - sfx_mario9 | 
| 91 - sfx_lose | 94 - sfx_mario2 | 
MAXNEWSOUNDS = 10
PICKUP_SOUND = 0x8000
- = 32768 (mask used to indicate sound origin is player item pickup)
 
sounds.h
NUMSKINSOUNDS = 25 (Total number of sounds for characters)
NUMMUSIC = 1049 (Total number of musicslots, including reserved tunes)
NUMSFX = 1090 (Total number of sounds, including freeslots)
NUMSFXFREESLOTS = 800
NUMSKINSFXSLOTS = 32*NUMSKINSOUNDS = 800
st_stuff.c/st_stuff.h
STARTBONUSPALS = 9
NUMBONUSPALS = 4
NUMHUDITEMS = 35 (Total number of HUD Items)
ST_drawDebugInfo
| 
|  Code - ST_drawDebugInfo |  
|  |  
| static void ST_drawDebugInfo(void)
{
	char smomx[33];
	char smomy[33];
	char smomz[33];
	char sspeed[33];
	char sfloorz[33];
	char spmomz[33];
	char scability[33];
	char scability2[33];
	char scharsped[33];
	char scharflags[33];
	char sstrcolor[33];
	char sdedtimer[33];
	char sjumpfact[33];
	char sx[33];
	char sy[33];
	char sz[33];
	char sangle[33];
	char sunderwater[33];
	char smfjumped[33];
	char smfspinning[33];
	char smfstartdash[33];
	char sjumping[33];
	char sscoreadd[33];
	if (!stplyr->mo)
		return;
	sprintf(smomx, "%d", stplyr->rmomx>>FRACBITS);
	sprintf(smomy, "%d", stplyr->rmomy>>FRACBITS);
	sprintf(smomz, "%d", stplyr->mo->momz>>FRACBITS);
	sprintf(sspeed, "%d", stplyr->speed);
	sprintf(sfloorz, "%d", stplyr->mo->floorz>>FRACBITS);
	sprintf(spmomz, "%d", stplyr->mo->ceilingz>>FRACBITS);
	sprintf(scability, "%d", stplyr->charability);
	sprintf(scability2, "%d", stplyr->charability2);
	sprintf(scharsped, "%d", stplyr->normalspeed);
	sprintf(scharflags, "%d", stplyr->charflags);
#ifdef TRANSFIX
	sprintf(sstrcolor, "%d", atoi(skins[stplyr->skin].starttranscolor));
#else
	sprintf(sstrcolor, "%d", stplyr->starttranscolor);
#endif
	sprintf(sdedtimer, "%d", stplyr->deadtimer);
	sprintf(sjumpfact, "%d", stplyr->jumpfactor);
	sprintf(sx, "%d", stplyr->mo->x>>FRACBITS);
	sprintf(sy, "%d", stplyr->mo->y>>FRACBITS);
	sprintf(sz, "%d", stplyr->mo->z>>FRACBITS);
	sprintf(sangle, "%d", stplyr->mo->angle>>FRACBITS);
	sprintf(sunderwater, "%d", stplyr->powers[pw_underwater]);
	sprintf(smfjumped, "%u", (stplyr->pflags & PF_JUMPED));
	sprintf(smfspinning, "%u", (stplyr->pflags & PF_SPINNING));
	sprintf(smfstartdash, "%u", (stplyr->pflags & PF_STARTDASH));
	sprintf(sjumping, "%d", stplyr->jumping);
	sprintf(sscoreadd, "%d", stplyr->scoreadd);
	V_DrawString(248, 0, 0, "MOMX =");
	V_DrawString(296, 0, 0, smomx);
	V_DrawString(248, 8, 0, "MOMY =");
	V_DrawString(296, 8, 0, smomy);
	V_DrawString(248, 16, 0, "MOMZ =");
	V_DrawString(296, 16, 0, smomz);
	V_DrawString(240, 24, 0, "SPEED =");
	V_DrawString(296, 24, 0, sspeed);
	V_DrawString(232, 32, 0, "FLOORZ=");
	V_DrawString(288, 32, 0, sfloorz);
	V_DrawString(240, 40, 0, "CEILZ =");
	V_DrawString(296, 40, 0, spmomz);
	V_DrawString(216, 48, 0, "CA =");
	V_DrawString(248, 48, 0, scability);
	V_DrawString(264, 48, 0, "CA2 =");
	V_DrawString(304, 48, 0, scability2);
	V_DrawString(216, 56, 0, "CHARSPED =");
	V_DrawString(296, 56, 0, scharsped);
	V_DrawString(216, 64, 0, "CHARFLGS =");
	V_DrawString(296, 64, 0, scharflags);
	V_DrawString(216, 72, 0, "STRCOLOR =");
	V_DrawString(296, 72, 0, sstrcolor);
	V_DrawString(216, 88, 0, "DEDTIMER =");
	V_DrawString(296, 88, 0, sdedtimer);
	V_DrawString(216, 96, 0, "JUMPFACT =");
	V_DrawString(296, 96, 0, sjumpfact);
	V_DrawString(240, 104, 0, "X =");
	V_DrawString(264, 104, 0, sx);
	V_DrawString(240, 112, 0, "Y =");
	V_DrawString(264, 112, 0, sy);
	V_DrawString(240, 120, 0, "Z =");
	V_DrawString(264, 120, 0, sz);
	V_DrawString(216, 128, 0, "Angle =");
	V_DrawString(272, 128, 0, sangle);
	V_DrawString(192, 152, 0, "Underwater =");
	V_DrawString(288, 152, 0, sunderwater);
	V_DrawString(192, 160, 0, "MF_JUMPED =");
	V_DrawString(288, 160, 0, smfjumped);
	V_DrawString(192, 168, 0, "MF_SPINNING =");
	V_DrawString(296, 168, 0, smfspinning);
	V_DrawString(192, 176, 0, "MF_STARDASH =");
	V_DrawString(296, 176, 0, smfstartdash);
	V_DrawString(192, 184, 0, "Jumping =");
	V_DrawString(288, 184, 0, sjumping);
	V_DrawString(192, 192, 0, "Scoreadd =");
	V_DrawString(288, 192, 0, sscoreadd);
} |  | 
ST_drawContinueHUD
| 
|  Code - ST_drawContinueHUD |  
|  |  
| static void ST_drawContinueHUD(void)
{
	char stimeleft[33];
	patch_t *contsonic;
	// Do continue screen here.
	// Initialize music
	// For some reason the code doesn't like a simple ==...
	if (stplyr->deadtimer < gameovertics && stplyr->deadtimer > gameovertics - 2)
	{
		// Force a screen wipe
		stplyr->deadtimer--;
		S_ChangeMusic(mus_contsc, false);
		S_StopSounds();
		oncontinuescreen = true;
		if (rendermode != render_none)
		{
			// First, read the current screen
			F_WipeStartScreen();
			// Then, draw what the new screen will look like.
			V_DrawFill(0, 0, vid.width, vid.height, 31);
			contsonic = W_CachePatchName("CONT1", PU_CACHE);
			V_DrawScaledPatch((BASEVIDWIDTH-SHORT(contsonic->width))/2, 64, 0, contsonic);
			V_DrawString(128,128,0, "CONTINUE?");
			sprintf(stimeleft, "%d", (stplyr->deadtimer - (gameovertics-11*TICRATE))/TICRATE);
			V_DrawString(stplyr->deadtimer >= (gameovertics-TICRATE) ? 152 : 160,144,0, stimeleft);
			// Now, read the end screen we want to fade to.
			F_WipeEndScreen(0, 0, vid.width, vid.height);
			// Do the wipe-io!
			F_RunWipe(2*TICRATE, true);
		}
	}
	V_DrawFill(0, 0, vid.width, vid.height, 31);
	V_DrawString(128, 128, 0, "CONTINUE?");
	// Draw a Sonic!
	contsonic = W_CachePatchName("CONT1", PU_CACHE);
	V_DrawScaledPatch((BASEVIDWIDTH - SHORT(contsonic->width))/2, 64, 0, contsonic);
	sprintf(stimeleft, "%d", (stplyr->deadtimer - (gameovertics-11*TICRATE))/TICRATE);
	V_DrawString(stplyr->deadtimer >= (gameovertics-TICRATE) ? 152 : 160, 144, 0, stimeleft);
	if (stplyr->deadtimer < (gameovertics-10*TICRATE))
		Command_ExitGame_f();
	if (stplyr->deadtimer < gameovertics-TICRATE && (stplyr->cmd.buttons & BT_JUMP || stplyr->cmd.buttons & BT_USE))
	{
		if (stplyr->continues != -1)
			stplyr->continues--;
		// Reset score
		stplyr->score = 0;
		// Allow tokens to come back if not a netgame.
		if (!(netgame || multiplayer))
		{
			tokenlist = 0;
			token = 0;
			imcontinuing = true;
		}
		// Reset # of lives
		if (ultimatemode)
			stplyr->lives = 1;
		else
			stplyr->lives = 3;
		// Clear any starpost data
		stplyr->starpostangle = 0;
		stplyr->starpostbit = 0;
		stplyr->starpostnum = 0;
		stplyr->starposttime = 0;
		stplyr->starpostx = 0;
		stplyr->starposty = 0;
		stplyr->starpostz = 0;
		contsonic = W_CachePatchName("CONT2", PU_CACHE);
		V_DrawScaledPatch((BASEVIDWIDTH - SHORT(contsonic->width))/2, 64, 0, contsonic);
	}
} |  | 
ST_drawEmeraldHuntIcon
| Distance from Emerald | Radar Color | Beeping interval | 
| 0 - 128 fracunits | Red | 5 tics | 
| 128 - 512 fracunits | Orange | 10 tics | 
| 512 - 1024 fracunits | Yellow | 20 tics | 
| 1024 - 2048 fracunits | Green | 30 tics | 
| 2048 - 3072 fracunits | Blue | 35 tics (1 second) | 
| 3072 fracunits or more | Grey | None | 
| 
|  Code - ST_drawEmeraldHuntIcon |  
|  |  
| static void ST_drawEmeraldHuntIcon(mobj_t *hunt, INT32 graphic)
{
	patch_t *p;
	INT32 interval;
	fixed_t dist = P_AproxDistance(P_AproxDistance(stplyr->mo->x - hunt->x, stplyr->mo->y - hunt->y),
		stplyr->mo->z - hunt->z);
	if (dist < 128<<FRACBITS)
	{
		p = homing6;
		interval = 5;
	}
	else if (dist < 512<<FRACBITS)
	{
		p = homing5;
		interval = 10;
	}
	else if (dist < 1024<<FRACBITS)
	{
		p = homing4;
		interval = 20;
	}
	else if (dist < 2048<<FRACBITS)
	{
		p = homing3;
		interval = 30;
	}
	else if (dist < 3072<<FRACBITS)
	{
		p = homing2;
		interval = 35;
	}
	else
	{
		p = homing1;
		interval = 0;
	}
	V_DrawScaledPatch(hudinfo[graphic].x, STRINGY(hudinfo[graphic].y), V_TRANSLUCENT, p);
	if (interval > 0 && leveltime % interval == 0)
		S_StartSound(NULL, sfx_emfind);
} |  | 
Other
Var1 >> 16 or Var2 >> 16 = Upper 16 bits
Var1 & 65535 or Var2 & 65535 = Lower 16 bits
Reaction time
(Not to be confused with the Object Info property called ReactionTime - that value is actually the starting value for the actor's reaction time, and doesn't change)
Actions that lower the actor's reaction time by 1 each time they are used:
Actions that perform effects when the actor's reaction time = 0:
Actions that set a new reaction time:
This value is set by adding a multiple of 4096 to the Thing Type number of the specified object.
- There are 16 possible values you can have for each Thing Type number (note that SRB2DB does not recognise extrainfoat all, and so will generally display Things withextrainfovalues of more than 0 as Unknown Thing Types):- 0: +0 (Regular Thing Type number)
- 1: +4096
- 2: +8192
- 3: +12288
- 4: +16384
- 5: +20480
- 6: +24576
- 7: +28672
- 8: +32768
- 9: +36864
- 10: +40960
- 11: +45056
- 12: +49152
- 13: +53248
- 14: +57344
- 15: +61440
 
List of SRB2 Thing Types that use extrainfo:
- Vanilla:
- XSRB2:
- Objects with MF_ENEMY- sets the starting size of the object:
 - extrainfo= 1: destscale = 50 (half regular size)
- extrainfo= 2: destscale = 200 (double regular size)
 
 - extrainfo= 1: destscale = 50 (half regular size)
 
 
Flame Jets
| Shooting strength | 
| Map Thing Number added | extrainfo/movedirvalue | Shooting strength | 
| +0 (Regular Map Thing number) | 0 | 20* FRACUNIT | 
| +4096 | 1 | 20* FRACUNIT- (20*FRACUNIT/16)*1= 20*
 FRACUNIT- 1.25*FRACUNIT= 18.75*
 FRACUNIT | 
| +8192 | 2 | 20* FRACUNIT- (20*FRACUNIT/16)*2= 20*
 FRACUNIT- 2.5*FRACUNIT= 17.5*
 FRACUNIT | 
| +12288 | 3 | 20* FRACUNIT- (20*FRACUNIT/16)*3= 20*
 FRACUNIT- 3.75*FRACUNIT= 16.25*
 FRACUNIT | 
| +16384 | 4 | 20* FRACUNIT- (20*FRACUNIT/16)*4= 20*
 FRACUNIT- 5*FRACUNIT= 15*
 FRACUNIT | 
| +20480 | 5 | 20* FRACUNIT- (20*FRACUNIT/16)*5= 20*
 FRACUNIT- 6.25*FRACUNIT= 13.75*
 FRACUNIT | 
| +24576 | 6 | 20* FRACUNIT- (20*FRACUNIT/16)*6= 20*
 FRACUNIT- 7.5*FRACUNIT= 12.5*
 FRACUNIT | 
| +28672 | 7 | 20* FRACUNIT- (20*FRACUNIT/16)*7= 20*
 FRACUNIT- 8.75*FRACUNIT= 11.25*
 FRACUNIT | 
| +32768 | 8 | 20* FRACUNIT- (20*FRACUNIT/16)*8= 20*
 FRACUNIT- 10*FRACUNIT= 10*
 FRACUNIT | 
| +36864 | 9 | 20* FRACUNIT- (20*FRACUNIT/16)*9= 20*
 FRACUNIT- 11.25*FRACUNIT= 8.75*
 FRACUNIT | 
| +40960 | 10 | 20* FRACUNIT- (20*FRACUNIT/16)*10= 20*
 FRACUNIT- 12.5*FRACUNIT= 7.5*
 FRACUNIT | 
| +45056 | 11 | 20* FRACUNIT- (20*FRACUNIT/16)*11= 20*
 FRACUNIT- 13.75*FRACUNIT= 6.25*
 FRACUNIT | 
| +49152 | 12 | 20* FRACUNIT- (20*FRACUNIT/16)*12= 20*
 FRACUNIT- 15*FRACUNIT= 5*
 FRACUNIT | 
| +53248 | 13 | 20* FRACUNIT- (20*FRACUNIT/16)*13= 20*
 FRACUNIT- 16.25*FRACUNIT= 3.75*
 FRACUNIT | 
| +57344 | 14 | 20* FRACUNIT- (20*FRACUNIT/16)*14= 20*
 FRACUNIT- 17.5*FRACUNIT= 2.5*
 FRACUNIT | 
| +61440 | 15 | 20* FRACUNIT- (20*FRACUNIT/16)*15=20*
 FRACUNIT- 18.75*FRACUNIT= 1.25*
 FRACUNIT | 
| Off time | 
| Angle ranges | thresholdvalue | Off time | 
| 0 - 1023 or 8192 - 9215
 or 16384 - 17407
 or 24576 - 25599
 | 0 | 2* TICRATE(Duration ofS_FLAMEJETSTND) + 1 (Duration ofS_FLAMEJETSTOP)= 70 + 1
 = 71 tics
 = 2 seconds + 1 tic (Default time)
 | 
| 1024 - 2047 or 9216 - 10239
 or 17408 - 18431
 or 25600 - 26623
 | 1 | 2* TICRATE+ 1*(TICRATE/2)= 70 + 17.5
 = 87.5 tics
 = 2.5 seconds
 | 
| 2048 - 3071 or 10240 - 11263
 or 18432 - 19455
 or 26624 - 27647
 | 2 | 2* TICRATE+ 2*(TICRATE/2)= 70 + 35
 = 105 tics
 = 3 seconds
 | 
| 3072 - 4095 or 11264 - 12287
 or 19456 - 20479
 or 27648 - 28671
 | 3 | 2* TICRATE+ 3*(TICRATE/2)= 70 + 52.5
 = 122.5 tics
 = 3.5 seconds
 | 
| 4096 - 5119 or 12288 - 13311
 or 20480 - 21503
 or 28672 - 29695
 | 4 | 2* TICRATE+ 4*(TICRATE/2)= 70 + 70
 = 140 tics
 = 4 seconds
 | 
| 5120 - 6143 or 13312 - 14335
 or 21504 - 22527
 or 29696 - 30719
 | 5 | 2* TICRATE+ 5*(TICRATE/2)= 70 + 87.5
 = 157.5 tics
 = 4.5 seconds
 | 
| 6144 - 7167 or 14336 - 15359
 or 22528 - 23551
 or 30720 - 31743
 | 6 | 2* TICRATE+ 6*(TICRATE/2)= 70 + 105
 = 175 tics
 = 5 seconds
 | 
| 7168 - 8191 or 15360 - 16383
 or 23552 - 24575
 or 31744 - 32767
 | 7 | 2* TICRATE+ 7*(TICRATE/2)= 70 + 122.5
 = 192.5 tics
 = 5.5 seconds
 | 
| On time | 
| Angle range | movecountvalue | On time | 
| 0 - 8191 | 0 | 3* TICRATE(Duration ofS_FLAMEJETSTART)= 105 tics
 = 3 seconds (Default time)
 | 
| 8192 - 16383 | 1 | 1*( TICRATE/2)= 17.5 tics
 = 0.5 seconds
 | 
| 16384 - 24575 | 2 | 2*( TICRATE/2)= 35 tics
 = 1 second
 | 
| 24576 - 32767 | 3 | 3*( TICRATE/2)= 52.5 tics
 = 1.5 seconds
 | 
Fan Particle Generator/A_ParticleSpawn
| Time interval | 
| Map Thing Number added | extrainfovalue | Time interval (tics) | 
| +0 (Regular Map Thing number) | 0 | 1 | 
| +4096 | 1 | 2 | 
| +8192 | 2 | 3 | 
| +12288 | 3 | 4 | 
| +16384 | 4 | 5 | 
| +20480 | 5 | 6 | 
| +24576 | 6 | 7 | 
| +28672 | 7 | 8 | 
| +32768 | 8 | 9 | 
| +36864 | 9 | 10 | 
| +40960 | 10 | 11 | 
| +45056 | 11 | 12 | 
| +49152 | 12 | 13 | 
| +53248 | 13 | 14 | 
| +57344 | 14 | 15 | 
| +61440 | 15 | 16 | 
| Particle rising speed | 
| Angle range | Speed (Fracunits) | 
| -32768 - -28673 | -8 | 
| -28672 - -24577 | -7 | 
| -24576 - -20481 | -6 | 
| -20480 - -16385 | -5 | 
| -16384 - -12289 | -4 | 
| -12288 - -8193 | -3 | 
| -8192 - -4097 | -2 | 
| -4096 - -1 | -1 | 
| 0 - 4095 | 0 | 
| 4096 - 8191 | 1 | 
| 8192 - 12287 | 2 | 
| 12288 - 16383 | 3 | 
| 16384 - 20479 | 4 | 
| 20480 - 24575 | 5 | 
| 24576 - 28671 | 6 | 
| 28672 - 32767 | 7 | 
| Particle shrinking speed | 
| Angle ranges | Shrinking Speed ( scalespeed) | 
| 0 - 255 or 16384 - 16639
 or -16384 - -16129
 or -32768 - -32513
 | 0 | 
| 256 - 511 or 16640 - 16895
 or -16128 - -15873
 or -32512 - -32257
 | 1 | 
| 512 - 767 or 16896 - 17151
 or -15872 - -15617
 or -32256 - -32001
 | 2 | 
| 768 - 1023 or 17152 - 17407
 or -15616 - -15361
 or -32000 - -31745
 | 3 | 
| 1024 - 1279 or 17408 - 17663
 or -15360 - -15105
 or -31744 - -31489
 | 4 | 
| 1280 - 1535 or 17664 - 17919
 or -15104 - -14849
 or -31488 - -31233
 | 5 | 
| 1536 - 1791 or 17920 - 18175
 or -14848 - -14593
 or -31232 - -30977
 | 6 | 
| 1792 - 2047 or 18176 - 18431
 or -14592 - -14337
 or -30976 - -30721
 | 7 | 
| 2048 - 2303 or 18432 - 18687
 or -14336 - -14081
 or -30720 - -30465
 | 8 | 
| 2304 - 2559 or 18688 - 18943
 or -14080 - -13825
 or -30464 - -30209
 | 9 | 
| 2560 - 2815 or 18944 - 19199
 or -13824 - -13569
 or -30208 - -29953
 | 10 | 
| 2816 - 3071 or 19200 - 19455
 or -13568 - -13313
 or -29952 - -29697
 | 11 | 
| 3072 - 3327 or 19456 - 19711
 or -13312 - -13057
 or -29696 - -29441
 | 12 | 
| 3328 - 3583 or 19712 - 19967
 or -13056 - -12801
 or -29440 - -29185
 | 13 | 
| 3584 - 3839 or 19968 - 20223
 or -12800 - -12545
 or -29184 - -28929
 | 14 | 
| 3840 - 4095 or 20224 - 20479
 or -12544 - -12289
 or -28928 - -28673
 | 15 | 
| 4096 - 4351 or 20480 - 20735
 or -12288 - -12033
 or -28672 - -28417
 | 16 | 
| 4352 - 4607 or 20736 - 20991
 or -12032 - -11777
 or -28416 - -28161
 | 17 | 
| 4608 - 4863 or 20992 - 21247
 or -11776 - -11521
 or -28160 - -27905
 | 18 | 
| 4864 - 5119 or 21248 - 21503
 or -11520 - -11265
 or -27904 - -27649
 | 19 | 
| 5120 - 5375 or 21504 - 21759
 or -11264 - -11009
 or -27648 - -27393
 | 20 | 
| 5376 - 5631 or 21760 - 22015
 or -11008 - -10753
 or -27392 - -27137
 | 21 | 
| 5632 - 5887 or 22016 - 22271
 or -10752 - -10497
 or -27136 - -26881
 | 22 | 
| 5888 - 6143 or 22272 - 22527
 or -10496 - -10241
 or -26880 - -26625
 | 23 | 
| 6144 - 6399 or 22528 - 22783
 or -10240 - -9985
 or -26624 - -26369
 | 24 | 
| 6400 - 6655 or 22784 - 23039
 or -9984 - -9729
 or -26368 - -26113
 | 25 | 
| 6656 - 6911 or 23040 - 23295
 or -9728 - -9473
 or -26112 - -25857
 | 26 | 
| 6912 - 7167 or 23296 - 23551
 or -9472 - -9217
 or -25856 - -25601
 | 27 | 
| 7168 - 7423 or 23552 - 23807
 or -9216 - -8961
 or -25600 - -25345
 | 28 | 
| 7424 - 7679 or 23808 - 24063
 or -8960 - -8705
 or -25344 - -25089
 | 29 | 
| 7680 - 7935 or 24064 - 24319
 or -8704 - -8449
 or -25088 - -24833
 | 30 | 
| 7936 - 8191 or 24320 - 24575
 or -8448 - -8193
 or -24832 - -24577
 | 31 | 
| 8192 - 8447 or 24576 - 24831
 or -8192 - -7937
 or -24576 - -24321
 | 32 | 
| 8448 - 8703 or 24832 - 25087
 or -7936 - -7681
 or -24320 - -24065
 | 33 | 
| 8704 - 8959 or 25088 - 25343
 or -7680 - -7425
 or -24064 - -23809
 | 34 | 
| 8960 - 9215 or 25344 - 25599
 or -7424 - -7169
 or -23808 - -23553
 | 35 | 
| 9216 - 9471 or 25600 - 25855
 or -7168 - -6913
 or -23552 - -23297
 | 36 | 
| 9472 - 9727 or 25856 - 26111
 or -6912 - -6657
 or -23296 - -23041
 | 37 | 
| 9728 - 9983 or 26112 - 26367
 or -6656 - -6401
 or -23040 - -22785
 | 38 | 
| 9984 - 10239 or 26368 - 26623
 or -6400 - -6145
 or -22784 - -22529
 | 39 | 
| 10240 - 10495 or 26624 - 26879
 or -6144 - -5889
 or -22528 - -22273
 | 40 | 
| 10496 - 10751 or 26880 - 27135
 or -5888 - -5633
 or -22272 - -22017
 | 41 | 
| 10752 - 11007 or 27136 - 27391
 or -5632 - -5377
 or -22016 - -21761
 | 42 | 
| 11008 - 11263 or 27392 - 27647
 or -5376 - -5121
 or -21760 - -21505
 | 43 | 
| 11264 - 11519 or 27648 - 27903
 or -5120 - -4865
 or -21504 - -21249
 | 44 | 
| 11520 - 11775 or 27904 - 28159
 or -4864 - -4609
 or -21248 - -20993
 | 45 | 
| 11776 - 12031 or 28160 - 28415
 or -4608 - -4353
 or -20992 - -20737
 | 46 | 
| 12032 - 12287 or 28416 - 28671
 or -4352 - -4097
 or -20736 - -20481
 | 47 | 
| 12288 - 12543 or 28672 - 28927
 or -4096 - -3841
 or -20480 - -20225
 | 48 | 
| 12544 - 12799 or 28928 - 29183
 or -3840 - -3585
 or -20224 - -19969
 | 49 | 
| 12800 - 13055 or 29184 - 29439
 or -3584 - -3328
 or -19968 - -19713
 | 50 | 
| 13056 - 13311 or 29440 - 29695
 or -3328 - -3073
 or -19712 - -19457
 | 51 | 
| 13312 - 13567 or 29696 - 29551
 or -3072 - -2817
 or -19456 - -19201
 | 52 | 
| 13568 - 13823 or 29552 - 30207
 or -2816 - -2561
 or -19200 - -18945
 | 53 | 
| 13824 - 14079 or 30208 - 30463
 or -2560 - -2305
 or -18944 - -18689
 | 54 | 
| 14080 - 14335 or 30464 - 30719
 or -2304 - -2049
 or -18688 - -18433
 | 55 | 
| 14336 - 14591 or 30720 - 30975
 or -2048 - -1793
 or -18432 - -18177
 | 56 | 
| 14592 - 14847 or 30976 - 31231
 or -1792 - -1537
 or -18176 - -17921
 | 57 | 
| 14848 - 15103 or 31232 - 31487
 or -1536 - -1281
 or -17920 - -17665
 | 58 | 
| 15104 - 15359 or 31488 - 31743
 or -1280 - -1025
 or -17664 - -17409
 | 59 | 
| 15360 - 15615 or 31743 - 31999
 or -1024 - -769
 or -17408 - -17153
 | 60 | 
| 15616 - 15871 or 32000 - 32255
 or -768 - -513
 or -17152 - -16897
 | 61 | 
| 15872 - 16127 or 32256 - 32511
 or -512 - -257
 or -16896 - -16641
 | 62 | 
| 16128 - 16383 or 32512 - 32767
 or -256 - -1
 or -16640 - -16385
 | 63 | 
Linedef Type Speeds
- Linedef type 3 - Zoom Tube Parameters: 1/8 FU/tic * FU X distance
- Linedef type 4 - Speed Pad: 1 FU/tic * FU length
- Linedef type 9 - Chain Parameters: ? FU/tic * FU Y distance
- Linedef type 11 - Rope Parameters: 1/8 FU/tic * FU X distance
- Linedef type 12 - Rock Parameters: 1/16 FU/tic * FU length
- Linedef type 30 - Waving Flag: 1 FU/tic * FU length
- Linedef type 52 - Continuously Falling Sector: 1 FU/tic * FU length
- Linedef Types 53, 54, 55: 1/4 FU/tic * FU length
- Linedef Types 56, 57, 58: 1/4 FU/tic * FU X distance/Y distance
- Linedef type 59 - Activate Floating Platform: 2 FU/tic
- Linedef type 60 - Activate Floating Platform (Adjustable Speed): 1/4 FU/tic * FU length
- Linedef type 61 - Crusher (Ceiling to Floor):
- Without Effect 4: 1/8 FU/tic * FU length
- With Effect 4: 1/4 FU/tic * FU X distance
 
- Linedef type 62 - Crusher (Floor to Ceiling):
- Without Effect 4: 1/16 FU/tic * FU length
- With Effect 4: 1/8 FU/tic * FU X distance
 
- Linedef Types 190, 191, 192, 193, 194, 195: 1/4 FU/tic * FU length
- Linedef type 257 - Quicksand: 1/70 FU/tic (or 1/2 FU/second) * FU X distance
- Linedef type 259 - Custom FOF: (FF_QUICKSAND) 1/70 FU/tic (or 1/2 FU/second) * FU X distance
- Linedef Types 403, 404: 1/8 FU/tic * FU length
- Linedef Types 405, 407: 1/8 FU/tic * FU X distance
- Linedef type 428 - Start Platform Movement: 1/4 FU/tic * FU length
- Linedef Types 429, 431:
- Without Effect 4: 1/8 FU/tic * FU length
- With Effect 4: 1/4 FU/tic * FU X distance
 
- Linedef type 430 - Crush Floor Once: 1/4 FU/tic * FU X distance
- Linedef type 480 - PolyObject Door Slide: 1/8 FU/tic * Front Texture X offset units
- Linedef type 481 - PolyObject Door Swing: ? FU/tic * Front Texture X offset units
- Linedef Types 482, 483: 1/8 FU/tic * Front Texture X offset units
- Linedef Types 484, 485, 486, 487: ? FU/tic * Front Texture X offset units
- Linedef type 488 - PolyObject Move By Waypoints: 1/8 FU/tic * Front Texture X offset units
- Linedef Types 500, 501: 1 FU/tic
- Linedef type 502 - Scroll Wall According To Linedef: 1/32 FU/tic * FU length
- Linedef Types 503, 504: (Base speed) 1/32 FU/tic * FU length
- Linedef type 505 - Scroll Texture By Front Side Offsets: 1 FU/tic * Front Texture offset units
- Linedef type 506 - Scroll Texture By Back Side Offsets: 1 FU/tic * Back Texture offset units
Character Skin Color Reference Sheets
Vanilla SRB2
| Value | Color Name | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 | #9 | #10 | #11 | #12 | #13 | #14 | #15 | #16 | 
| 1 | Cyan | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 
| 2 | Peach | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 
| 3 | Lavender | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 
| 4 | Silver | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
| 5 | Orange | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 
| 6 | Red | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 
| 7 | Blue | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 
| 8 | Steel Blue | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 
| 9 | Pink | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 
| 10 | Beige | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 
| 11 | Purple | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 
| 12 | Green | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 
| 13 | White | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
| 14 | Gold | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 
| 15 | Yellow | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 113 | 114 | 115 | 116 | 117 | 
SRB2CB
| Value | Color Name | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 | #9 | #10 | #11 | #12 | #13 | #14 | #15 | #16 | 
| 1 | Cyan | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 
| 2 | Peach | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 
| 3 | Lavender | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 
| 4 | Silver | 0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 
| 5 | Orange | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 
| 6 | Red | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 
| 7 | Blue | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 
| 8 | Steel Blue | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 
| 9 | Pink | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 
| 10 | Beige | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 
| 11 | Purple | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 
| 12 | Green | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 
| 13 | White | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
| 14 | Gold | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 
| 15 | Yellow | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 113 | 114 | 115 | 116 | 117 | 
| 16 | Black | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 
| 17 | Dark Red | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 
| 18 | Dark Blue | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 
| 19 | Neon Green | 184 | 185 | 186 | 187 | 
| 20 | Hot Pink | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 
| 21 | Brown | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 
SRB2 Riders
| Value | Color Name | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 | #9 | #10 | #11 | #12 | #13 | #14 | #15 | #16 | 
| 1 | Black | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 
| 2 | Grey | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 
| 3 | Silver | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
| 4 | White | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
| 5 | Pink | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 
| 6 | Light Red | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 
| 7 | Red | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 
| 8 | Dark Red | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 
| 9 | Purple | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 
| 10 | Lavender | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 
| 11 | Steel Blue | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 
| 12 | Dark Blue | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 
| 13 | Blue | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 
| 14 | Light Blue | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 
| 15 | Cyan | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 
| 16 | Neon Green | 184 | 185 | 186 | 187 | 
| 17 | Green | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 
| 18 | Army | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 
| 19 | Yellow | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 113 | 114 | 115 | 116 | 117 | 
| 20 | Gold | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 
| 21 | Orange | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 
| 22 | Peach | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 
| 23 | Beige | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 
| 24 | Brown | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 
| 25 | Rosewood | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 
Custom Skin Color Ideas
| Value | Color Name | #1 | #2 | #3 | #4 | #5 | #6 | #7 | #8 | #9 | #10 | #11 | #12 | #13 | #14 | #15 | #16 | 
| 16 | Cyan (Fixed) | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 
| 17 | Dark Orange | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 
| 18 | Dark Green | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 
| 19 | Dark Pink | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 
| 20 | Peach-Brown | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 
| 21 | Olive | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 31 | 
| 22 | Neon Green | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 
| 23 | Full-range Red | 120 | 121 | 123 | 124 | 126 | 127 | 129 | 130 | 132 | 133 | 135 | 136 | 138 | 139 | 141 | 143 | 
| 24 | Full-range Blue | 224 | 225 | 226 | 228 | 229 | 231 | 232 | 234 | 235 | 237 | 238 | 240 | 241 | 243 | 244 | 246 | 
| 25 | Full-range Orange | 80 | 81 | 83 | 85 | 86 | 88 | 90 | 91 | 93 | 95 | 152 | 153 | 154 | 156 | 157 | 159 | 
| 26 | Full-range Peach-Brown | 64 | 66 | 68 | 70 | 72 | 74 | 76 | 78 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 
| 27 | Robo-Hood Green | 177 | 178 | 165 | 167 | 182 | 171 | 183 | 173 | 
| 28 | Light Green | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 
| 29 | Light Orange | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 
| 30 | Light Steel Blue | 200 | 201 | 202 | 203 | 
| 31 | Light Army | 176 | 177 | 178 | 179 | 
| 32 | Teal | 220 | 221 | 222 | 223 | 
| 33 | Cerulean | 216 | 217 | 218 | 219 | 
| 34 | Salmon | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 
| 35 | Golden Brown | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 156 | 157 | 158 | 159 | 
| 36 | Dark Army | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 173 | 174 | 175 | 31 | 
| 37 | Dark Steel Blue | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 
| 38 | Lilac | 120 | 121 | 122 | 123 | 192 | 248 | 249 | 250 | 
| 39 | Pistachio | 176 | 177 | 178 | 179 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 
| 40 | Turquoise | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 220 | 221 | 222 | 223 | 
| 41 | Ivory | 120 | 0 | 1 | 2 | 4 | 6 | 8 | 10 | 
| 42 | Jet Black | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 28 | 29 | 30 | 31 | 
| 43 | Byzantium | 192 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 29 | 30 | 31 | 
| 44 | Indigo | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 255 | 29 | 30 | 31 | 
| 45 | Dark Neon Green | 187 | 188 | 189 | 190 | 191 | 175 | 30 | 31 | 
| 46 | Dark Rosewood | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 139 | 140 | 141 | 142 | 143 | 31 | 
Vanilla SRB2 Character S_SKINs
Actions originating from Doom
The 4 Source Code-only SOC Actions!
A_BossZoom
| Object Property | Use | 
| AttackSound | Attacking sound | 
| Speed | Speed ( Speed*5*FRACUNIT)
 | 
| 
|  Code - A_BossZoom |  
|  |  
| // Function: A_BossZoom
//
// Description: Like A_SkullAttack, but used by Boss 1.
//
// var1 = unused
// var2 = unused
//
void A_BossZoom(mobj_t *actor)
{
	mobj_t *dest;
	angle_t an;
	INT32 dist;
	if (!actor->target)
		return;
	dest = actor->target;
	actor->flags2 |= MF2_SKULLFLY;
	if (actor->info->attacksound)
		S_StartAttackSound(actor, actor->info->attacksound);
	A_FaceTarget(actor);
	an = actor->angle >> ANGLETOFINESHIFT;
	actor->momx = FixedMul(actor->info->speed*5*FRACUNIT, FINECOSINE(an));
	actor->momy = FixedMul(actor->info->speed*5*FRACUNIT, FINESINE(an));
	dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y);
	dist = dist / (actor->info->speed*5*FRACUNIT);
	if (dist < 1)
		dist = 1;
	actor->momz = (dest->z + (dest->height>>1) - actor->z) / dist;
} |  | 
A_Boss1Chase
| Object Property | Use | 
| MeleeState | Attack State #1 | 
| MissileState | Attack State #2 | 
| RaiseState | Pinch Phase Attack | 
| Damage | When the boss' health points reaches this value, start pinch phase | 
| Speed | Chasing Speed | 
| 
|  Code - A_Boss1Chase |  
|  |  
| // Function: A_Boss1Chase
//
// Description: Like A_Chase, but for Boss 1.
//
// var1 = unused
// var2 = unused
//
void A_Boss1Chase(mobj_t *actor)
{
	INT32 delta;
	if (actor->reactiontime)
		actor->reactiontime--;
	if (actor->z < actor->floorz+33*FRACUNIT)
		actor->z = actor->floorz+33*FRACUNIT;
	// turn towards movement direction if not there yet
	if (actor->movedir < NUMDIRS)
	{
		actor->angle &= (7<<29);
		delta = actor->angle - (actor->movedir << 29);
		if (delta > 0)
			actor->angle -= ANGLE_45;
		else if (delta < 0)
			actor->angle += ANGLE_45;
	}
	// do not attack twice in a row
	if (actor->flags2 & MF2_JUSTATTACKED)
	{
		actor->flags2 &= ~MF2_JUSTATTACKED;
		P_NewChaseDir(actor);
		return;
	}
	if (actor->movecount)
		goto nomissile;
	if (!P_CheckMissileRange(actor))
		goto nomissile;
	if (actor->reactiontime <= 0)
	{
		if (actor->health > actor->info->damage)
		{
			if (P_Random() & 1)
				P_SetMobjState(actor, actor->info->missilestate);
			else
				P_SetMobjState(actor, actor->info->meleestate);
		}
		else
			P_SetMobjState(actor, actor->info->raisestate);
		actor->flags2 |= MF2_JUSTATTACKED;
		actor->reactiontime = 2*TICRATE;
		return;
	}
	// ?
nomissile:
	// possibly choose another target
	if (multiplayer && P_Random() < 2)
	{
		if (P_LookForPlayers(actor, true, false, 0))
			return; // got a new target
	}
	// chase towards player
	if (--actor->movecount < 0 || !P_Move(actor, actor->info->speed))
		P_NewChaseDir(actor);
} |  | 
A_Boss2Chase
(If the actor is MT_EGGMOBILE2, actor->watertop = Speed)
Angle Increment
actor->target->angle += FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT))
Angle Increment = (Speed*(Spawnhealth*0.75))/(health*FRACUNIT)
| Egg Slimer - Angle Increment | 
| Health points | Angle Increment | 
| 8 | (2* FRACUNIT*(8*0.75))/(8*FRACUNIT)= (2*
 FRACUNIT*6)/(8*FRACUNIT)= (12*
 FRACUNIT)/(8*FRACUNIT)= 12/8
 = 1.5°
 | 
| 7 | (2* FRACUNIT*(8*0.75))/(7*FRACUNIT)= (2*
 FRACUNIT*6)/(7*FRACUNIT)= (12*
 FRACUNIT)/(7*FRACUNIT)= 12/7
 = ~1.71°
 | 
| 6 | (2* FRACUNIT*(8*0.75))/(6*FRACUNIT)= (2*
 FRACUNIT*6)/(6*FRACUNIT)= (12*
 FRACUNIT)/(6*FRACUNIT)= 12/6
 = 2°
 | 
| 5 | (2* FRACUNIT*(8*0.75))/(5*FRACUNIT)= (2*
 FRACUNIT*6)/(5*FRACUNIT)= (12*
 FRACUNIT)/(5*FRACUNIT)= 12/5
 = 2.4°
 | 
| 4 | (2* FRACUNIT*(8*0.75))/(4*FRACUNIT)= (2*
 FRACUNIT*6)/(4*FRACUNIT)= (12*
 FRACUNIT)/(4*FRACUNIT)= 12/4
 = 3°
 | 
| 3 | (2* FRACUNIT*(8*0.75))/(3*FRACUNIT)= (2*
 FRACUNIT*6)/(3*FRACUNIT)= (12*
 FRACUNIT)/(3*FRACUNIT)= 12/3
 = 4°
 | 
(Since the Egg Slimer pogos around instead for Health Points 2 and below, I won't list their values here. :P )
| Object Property | Use | 
| AttackSound | Goop Spraying Sound | 
| SpawnHealth | Used to set the Angle Increment | 
| PainChance | Object number of goop to spawn | 
| Speed | Used to set Angle Increment | 
| 
|  Code - A_Boss2Chase |  
|  |  
| // Function: A_Boss2Chase
//
// Description: Really doesn't 'chase', but rather goes in a circle.
//
// var1 = unused
// var2 = unused
//
void A_Boss2Chase(mobj_t *actor)
{
	fixed_t radius;
	boolean reverse = false;
	INT32 speedvar;
	if (actor->health <= 0)
		return;
	// When reactiontime hits zero, he will go the other way
	if (actor->reactiontime)
		actor->reactiontime--;
	if (actor->reactiontime <= 0)
	{
		reverse = true;
		actor->reactiontime = 2*TICRATE + P_Random();
	}
	P_SetTarget(&actor->target, P_GetClosestAxis(actor));
	if (!actor->target) // This should NEVER happen.
	{
		CONS_Printf("Error: Boss2 has no target!\n");
		A_BossDeath(actor);
		return;
	}
	radius = actor->target->radius;
	if (reverse)
		actor->watertop = -actor->watertop;
	// Only speed up if you have the 'Deaf' flag.
	if (actor->flags & MF_AMBUSH)
		speedvar = actor->health;
	else
		speedvar = actor->info->spawnhealth;
	actor->target->angle += FixedAngle(FixedDiv(FixedMul(actor->watertop, (actor->info->spawnhealth*(FRACUNIT/4)*3)), speedvar*FRACUNIT)); // Don't use FixedAngleC!
	P_UnsetThingPosition(actor);
	{
		const angle_t fa = actor->target->angle>>ANGLETOFINESHIFT;
		const fixed_t fc = FixedMul(FINECOSINE(fa),radius);
		const fixed_t fs = FixedMul(FINESINE(fa),radius);
		actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x + fc, actor->target->y + fs);
		actor->x = actor->target->x + fc;
		actor->y = actor->target->y + fs;
	}
	P_SetThingPosition(actor);
	// Spray goo once every second
	if (leveltime % (speedvar*15/10)-1 == 0)
	{
		const fixed_t ns = 3 * FRACUNIT;
		mobj_t *goop;
		fixed_t fz = actor->z+actor->height+56*FRACUNIT;
		angle_t fa;
		// actor->movedir is used to determine the last
		// direction goo was sprayed in. There are 8 possible
		// directions to spray. (45-degree increments)
		actor->movedir++;
		actor->movedir %= NUMDIRS;
		fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
		goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
		goop->momx = FixedMul(FINESINE(fa),ns);
		goop->momy = FixedMul(FINECOSINE(fa),ns);
		goop->momz = 4*FRACUNIT;
		goop->fuse = 30*TICRATE+P_Random();
		if (actor->info->attacksound)
			S_StartAttackSound(actor, actor->info->attacksound);
		if (P_Random() & 1)
		{
			goop->momx *= 2;
			goop->momy *= 2;
		}
		else if (P_Random() > 128)
		{
			goop->momx *= 3;
			goop->momy *= 3;
		}
		actor->flags2 |= MF2_JUSTATTACKED;
	}
} |  | 
A_Boss2Pogo
| Object Property | Use | 
| RaiseState | Pogoing state | 
| AttackSound | Pogoing sound | 
| PainChance | Object number of goop to spawn | 
| 
|  Code - A_Boss2Pogo |  
|  |  
| // Function: A_Boss2Pogo
//
// Description: Pogo part of Boss 2 AI.
//
// var1 = unused
// var2 = unused
//
void A_Boss2Pogo(mobj_t *actor)
{
	if (actor->z <= actor->floorz + 8*FRACUNIT && actor->momz <= 0)
	{
		P_SetMobjState(actor, actor->info->raisestate);
		// Pogo Mode
	}
	else if (actor->momz < 0 && actor->reactiontime)
	{
		const fixed_t ns = 3 * FRACUNIT;
		mobj_t *goop;
		fixed_t fz = actor->z+actor->height+56*FRACUNIT;
		angle_t fa;
		INT32 i;
		// spray in all 8 directions!
		for (i = 0; i < 8; i++)
		{
			actor->movedir++;
			actor->movedir %= NUMDIRS;
			fa = (actor->movedir*FINEANGLES/8) & FINEMASK;
			goop = P_SpawnMobj(actor->x, actor->y, fz, actor->info->painchance);
			goop->momx = FixedMul(FINESINE(fa),ns);
			goop->momy = FixedMul(FINECOSINE(fa),ns);
			goop->momz = 4*FRACUNIT;
#ifdef CHAOSISNOTDEADYET
			if (gametype == GT_CHAOS)
				goop->fuse = 15*TICRATE;
			else
#endif
				goop->fuse = 30*TICRATE+P_Random();
		}
		actor->reactiontime = 0;
		if (actor->info->attacksound)
			S_StartAttackSound(actor, actor->info->attacksound);
		actor->flags2 |= MF2_JUSTATTACKED;
	}
} |  | 
Test Wads
- FanParticleGenTest2.wad - Basically some test map showcasing 128 of the different angles you can set for Fan Particle Generators
Colormaps used in Vanilla SRB2
| Name | Hex code (General color) | Hex code (Fade) | 
| Generic Water | #40A0FFJ | Default (Black) | 
| THZ Slime | #E000E0S | Default (Black) | 
| THZ Alarm Floodlight | #FF0000Z | Default (Black) | 
| ACZ Water | #0004FFJ | Default (Black) | 
| RVZ Lava | #FF7F00Z | #FF7F00Z | 
| ERZ1 Fog #1 | #7F7F7FZ | #7F7F7FZ | 
| ERZ1 Fog #2 | #0000FFZ | #0000FFZ | 
| ERZ2 Acid | #999999D | #00FF00Z | 
| ERZ2 Gravity Change section Fog | #FF0000A | #FF00006 | 
| ERZ2 Teleport Fog | #999999D | #FFFF00Z | 
| ERZ2 Misc Fog #1 | #00AAFF0 | #00AAFF0 | 
| ERZ2 Misc Fog #2 | #FFFFFFF | #00FF000 | 
| ERZ2 Misc Fog #3 | #999999D | #0000FFZ | 
| ERZ2 Final Area Fog #1 | #FF5500A | #FF55000 | 
| ERZ2 Final Area Fog #2 | #FF6600A | #FF66000 |