Shell Effects
Additional features
Adding weapons to the shell.
The shell only covers the player model, because weapons are passed to the renderer as separate entities.

In order for the shell to include additional models we need to work on the function CL_AddPacketEntities in client\cl_ents.c
		// color shells generate a seperate entity for the main model
		if (effects & EF_COLOR_SHELL)
		{
			// PMM - at this point, all of the shells have been handled
			// if we're in the rogue pack, set up the custom mixing, otherwise just
			// keep going
//			if(Developer_searchpath(2) == 2)
//			{
				// all of the solo colors are fine.  we need to catch any of the combinations that look bad
				// (double & half) and turn them into the appropriate color, and make double/quad something special
				if (renderfx & RF_SHELL_HALF_DAM)
				{
					if(Developer_searchpath(2) == 2)
					{
						// ditch the half damage shell if any of red, blue, or double are on
						if (renderfx & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_DOUBLE))
							renderfx &= ~RF_SHELL_HALF_DAM;
					}
				}

				if (renderfx & RF_SHELL_DOUBLE)
				{
					if(Developer_searchpath(2) == 2)
					{
						// lose the yellow shell if we have a red, blue, or green shell
						if (renderfx & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN))
							renderfx &= ~RF_SHELL_DOUBLE;
						// if we have a red shell, turn it to purple by adding blue
						if (renderfx & RF_SHELL_RED)
							renderfx |= RF_SHELL_BLUE;
						// if we have a blue shell (and not a red shell), turn it to cyan by adding green
						else if (renderfx & RF_SHELL_BLUE)
							// go to green if it's on already, otherwise do cyan (flash green)
							if (renderfx & RF_SHELL_GREEN)
								renderfx &= ~RF_SHELL_BLUE;
							else
								renderfx |= RF_SHELL_GREEN;
					}
				}
//			}
			// pmm
			ent.flags = renderfx | RF_TRANSLUCENT;
			ent.alpha = 0.30;
			V_AddEntity (&ent);
		}

		ent.skin = NULL;		// never use a custom skin on others
		ent.skinnum = 0;
		ent.flags = 0;
		ent.alpha = 0;

Add in the section near the bottom after the line which says // c14 add linked models under shell
		// color shells generate a seperate entity for the main model
		if (effects & EF_COLOR_SHELL)
		{
			// PMM - at this point, all of the shells have been handled
			// if we're in the rogue pack, set up the custom mixing, otherwise just
			// keep going
//			if(Developer_searchpath(2) == 2)
//			{
				// all of the solo colors are fine.  we need to catch any of the combinations that look bad
				// (double & half) and turn them into the appropriate color, and make double/quad something special
				if (renderfx & RF_SHELL_HALF_DAM)
				{
					if(Developer_searchpath(2) == 2)
					{
						// ditch the half damage shell if any of red, blue, or double are on
						if (renderfx & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_DOUBLE))
							renderfx &= ~RF_SHELL_HALF_DAM;
					}
				}

				if (renderfx & RF_SHELL_DOUBLE)
				{
					if(Developer_searchpath(2) == 2)
					{
						// lose the yellow shell if we have a red, blue, or green shell
						if (renderfx & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN))
							renderfx &= ~RF_SHELL_DOUBLE;
						// if we have a red shell, turn it to purple by adding blue
						if (renderfx & RF_SHELL_RED)
							renderfx |= RF_SHELL_BLUE;
						// if we have a blue shell (and not a red shell), turn it to cyan by adding green
						else if (renderfx & RF_SHELL_BLUE)
							// go to green if it's on already, otherwise do cyan (flash green)
							if (renderfx & RF_SHELL_GREEN)
								renderfx &= ~RF_SHELL_BLUE;
							else
								renderfx |= RF_SHELL_GREEN;
					}
				}

//			}
			// pmm
			ent.flags = renderfx | RF_TRANSLUCENT;
			ent.alpha = 0.30;
			V_AddEntity (&ent);

// c14 add linked models under shell

			// duplicate for linked models
			if (s1->modelindex2)
			{
				if (s1->modelindex2 == 255)
				{	// custom weapon
					ci = &cl.clientinfo[s1->skinnum & 0xff];
					i = (s1->skinnum >> 8); // 0 is default weapon model
					if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
						i = 0;
					ent.model = ci->weaponmodel[i];
					if (!ent.model) {
						if (i != 0)
							ent.model = ci->weaponmodel[0];
						if (!ent.model)
							ent.model = cl.baseclientinfo.weaponmodel[0];
					}
				}
				else
					ent.model = cl.model_draw[s1->modelindex2];

				V_AddEntity (&ent);

			}
			if (s1->modelindex3)
			{
				ent.model = cl.model_draw[s1->modelindex3];
				V_AddEntity (&ent);
			}
			if (s1->modelindex4)
			{
				ent.model = cl.model_draw[s1->modelindex4];
				V_AddEntity (&ent);
			}

		}

		ent.skin = NULL;		// never use a custom skin on others
		ent.skinnum = 0;
		ent.flags = 0;
		ent.alpha = 0;
Adding a glow to the shell.
The shell does not cast any light, even though we kind of expect it to be a "glowing" shell. Actually we could in theory have black shells, but implementing them would be a huge task.

We'll add a dynamic light with the shell and this will illuminate the walls around the model, and also the model itself

The changes also need to be made in CL_AddPacketEntities in client\cl_ents.c<\tt>
		if (s1->number == cl.playernum+1)
		{
			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
			// FIXME: still pass to refresh

			if (effects & EF_FLAG1)
				V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
			else if (effects & EF_FLAG2)
				V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
			else if (effects & EF_TAGTRAIL)						//PGM
				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);	//PGM
			else if (effects & EF_TRACKERTRAIL)					//PGM
				V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);	//PGM

			continue;
		}

		// if set to invisible, skip
		if (!s1->modelindex)
			continue;
Add in the section near the bottom after the line which says // c14 illuminating shells
		if (s1->number == cl.playernum+1)
		{
			ent.flags |= RF_VIEWERMODEL;	// only draw from mirrors
			// FIXME: still pass to refresh

			if (effects & EF_FLAG1)
				V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1);
			else if (effects & EF_FLAG2)
				V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0);
			else if (effects & EF_TAGTRAIL)						//PGM
				V_AddLight (ent.origin, 225, 1.0, 1.0, 0.0);	//PGM
			else if (effects & EF_TRACKERTRAIL)					//PGM
				V_AddLight (ent.origin, 225, -1.0, -1.0, -1.0);	//PGM

			continue;
		}

		// c14 illuminating shells
		if (renderfx & RF_SHELL_RED)
			V_AddLight(ent.origin, 100, 1.0, 0.0, 0.0);
		if (renderfx & RF_SHELL_BLUE)
			V_AddLight(ent.origin, 100, 0.0, 0.0, 1.0);
		if (renderfx & RF_SHELL_GREEN)
			V_AddLight(ent.origin, 100, 0.0, 1.0, 0.0);

		// if set to invisible, skip
		if (!s1->modelindex)
			continue;
You might want to extend this code to deal with RF_SHELL_DOUBLE and RF_SHELL_HALF_DAM.

The function V_AddLight takes 5 parameters.
  • The origin of the light. (We use the origin of the player.)
  • The intensity of the light. (100 will just cast a light on the walls if you're very close.)
  • The red component on a scale from 0 to 1.
  • The green component.
  • The blue component.
Adding a glow to the view weapon.
When you have a colored shell, then typically there is a colored blend over the entire view, but this is controlled by the game not by the engine.

We'll add the same shell effect that other players see, to your own view weapon.

The changes need to be made in CL_AddViewWeapon in client\cl_ents.c<\tt>
/*
==============
CL_AddViewWeapon
==============
*/
void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
{
	entity_t	gun;		// view model
	int			i;

	// allow the gun to be completely removed
	if (!cl_gun->value)
		return;

	// don't draw gun if in wide angle view
	if (ps->fov > 90)
		return;

	memset (&gun, 0, sizeof(gun));

	if (gun_model)
		gun.model = gun_model;	// development tool
	else
		gun.model = cl.model_draw[ps->gunindex];
	if (!gun.model)
		return;

	// set up gun position
	for (i=0 ; i<3 ; i++)
	{
		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
			ps->gunangles[i], cl.lerpfrac);
	}

	if (gun_frame)
	{
		gun.frame = gun_frame;	// development tool
		gun.oldframe = gun_frame;	// development tool
	}
	else
	{
		gun.frame = ps->gunframe;
		if (gun.frame == 0)
			gun.oldframe = 0;	// just changed weapons, don't lerp from old
		else
			gun.oldframe = ops->gunframe;
	}

	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
	gun.backlerp = 1.0 - cl.lerpfrac;
	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
	V_AddEntity (&gun);

}
Add two lines near the top, and the section near the bottom after the line which says // c14 add shell to view model
/*
==============
CL_AddViewWeapon
==============
*/
void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
{
	entity_t	gun;		// view model
	int			i;
	int pnum;				// c14 add shell to view model
	entity_state_t *s1;		// c14 add shell to view model


	// allow the gun to be completely removed
	if (!cl_gun->value)
		return;

	// don't draw gun if in wide angle view
	if (ps->fov > 90)
		return;

	memset (&gun, 0, sizeof(gun));

	if (gun_model)
		gun.model = gun_model;	// development tool
	else
		gun.model = cl.model_draw[ps->gunindex];
	if (!gun.model)
		return;

	// set up gun position
	for (i=0 ; i<3 ; i++)
	{
		gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
			+ cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
		gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
			ps->gunangles[i], cl.lerpfrac);
	}

	if (gun_frame)
	{
		gun.frame = gun_frame;	// development tool
		gun.oldframe = gun_frame;	// development tool
	}
	else
	{
		gun.frame = ps->gunframe;
		if (gun.frame == 0)
			gun.oldframe = 0;	// just changed weapons, don't lerp from old
		else
			gun.oldframe = ops->gunframe;
	}

	gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
	gun.backlerp = 1.0 - cl.lerpfrac;
	VectorCopy (gun.origin, gun.oldorigin);	// don't lerp at all
	V_AddEntity (&gun);

	// c14 add shell to view model
	for (pnum = 0 ; pnum<cl.frame.num_entities ; pnum++)
	{
		s1 = &cl_parse_entities[(cl.frame.parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
		if (s1->number != cl.playernum + 1)
			continue;

		if (s1->effects & (EF_COLOR_SHELL|EF_QUAD|EF_PENT|EF_DOUBLE|EF_HALF_DAMAGE))
		{
			gun.flags |= (RF_TRANSLUCENT|s1->renderfx);
			if (s1->effects & EF_PENT)
				gun.flags |= RF_SHELL_RED;
			if (s1->effects & EF_QUAD)
				gun.flags |= RF_SHELL_BLUE;
			if (s1->effects & EF_DOUBLE)
				gun.flags |= RF_SHELL_DOUBLE;
			if (s1->effects & EF_HALF_DAMAGE)
				gun.flags |= RF_SHELL_HALF_DAM;
			gun.alpha = 0.1;
			V_AddEntity(&gun);
		}
	}
}