Tutorial *110*

The blue quad globe and red pent globe (and purple when you have them both) look great in GLQW, heres how to get them into NQ. Unfortunetly they must be programmed into the QC too, so this wont make them suddenly appear in your old mods :( Open gl_model.h and below the line



#define EF_DIMLIGHT 			8

add the following 2 lines


#define EF_BLUE					64

#define EF_RED					128

Next open client.h, find and change the typdef struct of dlight_t to look like this:


typedef struct

{

	vec3_t	origin;

	float	radius;

	float	die;				// stop lighting after this time

	float	decay;				// drop this each second

	float	minlight;			// don't add when contributing less

	int		key;

	float   color[4];			//Added to allow coloured Globes

#ifdef QUAKE2

	qboolean	dark;			// subtracts light instead of adding

#endif

} dlight_t;

Now open gl_rlight.c and find the R_RenderDlight function. Edit it to look like this :


void R_RenderDlight (dlight_t *light)

{

	int		i, j;

	float	a;

	vec3_t	v;

	float	rad;



	rad = light->radius * 0.35;



	VectorSubtract (light->origin, r_origin, v);

	if (Length (v) < rad)

	{	// view is inside the dlight

		AddLightBlend (1, 0.5, 0, light->radius * 0.0003);

		return;

	}



	glBegin (GL_TRIANGLE_FAN);



	//glColor3f (0.2,0.1,0.0); Commented out the old single color globe method

	//Use the following line to allow multiple coloured dlights/globes.

	glColor4f (light->color[0], light->color[1], light->color[2], light->color[3]);



	for (i=0 ; i<3 ; i++)

		v[i] = light->origin[i] - vpn[i]*rad;

	glVertex3fv (v);

	glColor3f (0,0,0);

	for (i=16 ; i>=0 ; i--)

	{

		a = i/16.0 * M_PI*2;

		for (j=0 ; j<3 ; j++)

			v[j] = light->origin[j] + vright[j]*cos(a)*rad

				+ vup[j]*sin(a)*rad;

		glVertex3fv (v);

	}

	glEnd ();

}

Now open gl_rlight.c and find the R_RenderDlight function. Edit it to look like this :


void R_RenderDlight (dlight_t *light)

{

	int		i, j;

	float	a;

	vec3_t	v;

	float	rad;



	rad = light->radius * 0.35;



	VectorSubtract (light->origin, r_origin, v);

	if (Length (v) < rad)

	{	// view is inside the dlight

		AddLightBlend (1, 0.5, 0, light->radius * 0.0003);

		return;

	}



	glBegin (GL_TRIANGLE_FAN);



	//glColor3f (0.2,0.1,0.0); Commented out the old single color globe method

	//Use the following line to allow multiple coloured dlights/globes.

	glColor4f (light->color[0], light->color[1], light->color[2], light->color[3]);



	for (i=0 ; i<3 ; i++)

		v[i] = light->origin[i] - vpn[i]*rad;

	glVertex3fv (v);

	glColor3f (0,0,0);

	for (i=16 ; i>=0 ; i--)

	{

		a = i/16.0 * M_PI*2;

		for (j=0 ; j<3 ; j++)

			v[j] = light->origin[j] + vright[j]*cos(a)*rad

				+ vup[j]*sin(a)*rad;

		glVertex3fv (v);

	}

	glEnd ();

}

OK, finally you have to make the right colours get assigned to the right entities. Open cl_main.c and find the CL_RelinkEntities function. Change it to look like this :


/*

===============

CL_RelinkEntities

===============

*/

void CL_RelinkEntities (void)

{

	entity_t	*ent;

	int			i, j;

	float		frac, f, d;

	vec3_t		delta;

	float		bobjrotate;

	vec3_t		oldorg;

	dlight_t	*dl;



// determine partial update time

	frac = CL_LerpPoint ();



	cl_numvisedicts = 0;



//

// interpolate player info

//

	for (i=0 ; i<3 ; i++)

		cl.velocity[i] = cl.mvelocity[1][i] +

			frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);



	if (cls.demoplayback)

	{

	// interpolate the angles

		for (j=0 ; j<3 ; j++)

		{

			d = cl.mviewangles[0][j] - cl.mviewangles[1][j];

			if (d > 180)

				d -= 360;

			else if (d < -180)

				d += 360;

			cl.viewangles[j] = cl.mviewangles[1][j] + frac*d;

		}

	}



	bobjrotate = anglemod(100*cl.time);



// start on the entity after the world

	for (i=1,ent=cl_entities+1 ; imodel)

		{	// empty slot

			if (ent->forcelink)

				R_RemoveEfrags (ent);	// just became empty

			continue;

		}



// if the object wasn't included in the last packet, remove it

		if (ent->msgtime != cl.mtime[0])

		{

			ent->model = NULL;

			continue;

		}



		VectorCopy (ent->origin, oldorg);



		if (ent->forcelink)

		{	// the entity was not updated in the last message

			// so move to the final spot

			VectorCopy (ent->msg_origins[0], ent->origin);

			VectorCopy (ent->msg_angles[0], ent->angles);

		}

		else

		{	// if the delta is large, assume a teleport and don't lerp

			f = frac;

			for (j=0 ; j<3 ; j++)

			{

				delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];

				if (delta[j] > 100 || delta[j] < -100)

					f = 1;		// assume a teleportation, not a motion

			}



		// interpolate the origin and angles

			for (j=0 ; j<3 ; j++)

			{

				ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];



				d = ent->msg_angles[0][j] - ent->msg_angles[1][j];

				if (d > 180)

					d -= 360;

				else if (d < -180)

					d += 360;

				ent->angles[j] = ent->msg_angles[1][j] + f*d;

			}



		}



// rotate binary objects locally

		if (ent->model->flags & EF_ROTATE)

			ent->angles[1] = bobjrotate;



		if (ent->effects & EF_BRIGHTFIELD)

			R_EntityParticles (ent);

#ifdef QUAKE2

		if (ent->effects & EF_DARKFIELD)

			R_DarkFieldParticles (ent);

#endif



/* OK from here down there are changes to assign globe colours.

Note that now we have to set colours for the old default coloured globes or they dont

appear at all. You could set different colours for rockets and muzzle flashes etc

if it took your fancy.

*/



		if (ent->effects & EF_MUZZLEFLASH)

		{

			vec3_t		fv, rv, uv;



			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->origin[2] += 16;

			AngleVectors (ent->angles, fv, rv, uv);



			VectorMA (dl->origin, 18, fv, dl->origin);

			dl->radius = 200 + (rand()&31);

			dl->minlight = 32;

			dl->die = cl.time + 0.1;

			dl->color[0] = 0.2;

			dl->color[1] = 0.1;

			dl->color[2] = 0.05;

			dl->color[3] = 0.7;

		}

		if (ent->effects & EF_BRIGHTLIGHT)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->origin[2] += 16;

			dl->radius = 400 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->color[0] = 0.2;

			dl->color[1] = 0.1;

			dl->color[2] = 0.05;

			dl->color[3] = 0.7;

		}

		if (ent->effects & EF_DIMLIGHT)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->color[0] = 0.2;

			dl->color[1] = 0.1;

			dl->color[2] = 0.05;

			dl->color[3] = 0.7;

		}

		if (ent->effects & EF_BLUE)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->color[0] = 0.05;

			dl->color[1] = 0.05;

			dl->color[2] = 0.3;

			dl->color[3] = 0.7;

		}

		if (ent->effects & EF_RED)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->color[0] = 0.5;

			dl->color[1] = 0.05;

			dl->color[2] = 0.05;

			dl->color[3] = 0.7;

		}

		if ((ent->effects & (EF_BLUE | EF_RED)) == (EF_BLUE | EF_RED))

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->color[0]=0.5;

			dl->color[1] = 0.05;

			dl->color[2] = 0.4;

			dl->color[3] = 0.7;

		}

#ifdef QUAKE2

		if (ent->effects & EF_DARKLIGHT)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200.0 + (rand()&31);

			dl->die = cl.time + 0.001;

			dl->dark = true;

		}

		if (ent->effects & EF_LIGHT)

		{

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin,  dl->origin);

			dl->radius = 200;

			dl->die = cl.time + 0.001;

		}

#endif



		if (ent->model->flags & EF_GIB)

			R_RocketTrail (oldorg, ent->origin, 2);

		else if (ent->model->flags & EF_ZOMGIB)

			R_RocketTrail (oldorg, ent->origin, 4);

		else if (ent->model->flags & EF_TRACER)

			R_RocketTrail (oldorg, ent->origin, 3);

		else if (ent->model->flags & EF_TRACER2)

			R_RocketTrail (oldorg, ent->origin, 5);

		else if (ent->model->flags & EF_ROCKET)

		{

			R_RocketTrail (oldorg, ent->origin, 0);

			dl = CL_AllocDlight (i);

			VectorCopy (ent->origin, dl->origin);

			dl->radius = 200;

			dl->die = cl.time + 0.01;

			dl->color[0] = 0.2;

			dl->color[1] = 0.1;

			dl->color[2] = 0.05;

			dl->color[3] = 0.7;



		}

		else if (ent->model->flags & EF_GRENADE)

			R_RocketTrail (oldorg, ent->origin, 1);

		else if (ent->model->flags & EF_TRACER3)

			R_RocketTrail (oldorg, ent->origin, 6);



		ent->forcelink = false;



		if (i == cl.viewentity && !chase_active.value)

			continue;



#ifdef QUAKE2

		if ( ent->effects & EF_NODRAW )

			continue;

#endif

		if (cl_numvisedicts < MAX_VISEDICTS)

		{

			cl_visedicts[cl_numvisedicts] = ent;

			cl_numvisedicts++;

		}

	}



}

OK, now compile, and if I havent missed out anything it should work :P Note that I havent added colour info to the effects within the #ifdef quake2 bits. If you were using these just add some dl->colour lines to get the working right again. If you are looking at and understanding the code you have been changing that shouldnt be a problem for you. For homework try to add EF_GREEN yourself. If u try and fail u can get the code from me. color[0] is the transparency level.

Altering QC to put the effects into the game


I have only done this with frogbot source QC so far, but it ought to be similar for basic QC. Open defs.qc and do a find on EF_BLUE. It will be within a #ifdef QUAKEWORLD. Comment out the #ifdef and the #endif :


//#ifdef QUAKEWORLD -- comment this out

// GLQuakeWorld Stuff

float EF_BLUE		= 64;	// Blue Globe effect for Quad

float EF_RED		= 128;	// Red Globe effect for Pentagram



float EF_DIMLIGHT_BLUE	= 72;

float EF_DIMLIGHT_RED	= 136;







float NOT_EF_BLUE		= 16777151;

float NOT_EF_RED		= 16777087;



//#endif // QUAKEWORLD -- this too

If you are adding this to non frogbot code, FIND on EF_DIMLIGHT and add the above below it. I've only added it to frogbot code so I don't know for sure that would work, sorry.

OK finally open items.qc and change the item functions to set the entity attributes. This is what frogbot code should look like once you are finished. [Ed: You can easily plug the the QW QC into normal quake, okay I'll shut up now]



/*

===============================================================================



POWERUPS



===============================================================================

*/



void() powerup_touch =

{

	if (other.client_)

	{

		if (marker_time)

			check_marker();



	#ifdef MANUAL

		if (manual_mode)

			return;

	#endif // MANUAL



		if (self.nextthink)

			return;

		if (other.takedamage)

		{

			if (other.goalentity == self)

				other.goal_refresh_time = 0;



			self.nextthink = self.goal_respawn_time = time + self.aflag;

			AssignVirtualGoal();



			msg_entity = other;

			msg_level = PRINT_LOW;



			sprint ("You got the ");

			sprint (self.netname);

			sprint ("\n");



			sound (CHAN_VOICE, self.noise, 1, ATTN_NORM);



			bf();



			self.model = "";



			items_ = self.items;



		// do the apropriate action

			if (items_ == IT_INVISIBILITY)

			{

			// use the eyes

			#ifdef QUAKE

				if (other.flags & FL_PLAYER)

				{

					if (game_skinfix)

					{

						other.modelindex = 0;

						other.aiment.modelindex = modelindex_eyes;

						msg_entity = other;

						WriteByte(MSG_ONE, SVC_SETVIEWPORT);

						WriteEntity(MSG_ONE, other.aiment);

					}

					else

						other.modelindex = modelindex_eyes;

				}

				else

				{

					other.aiment.modelindex = 0;

					other.modelindex = modelindex_eyes;

				}

			#endif // QUAKE



			#ifdef QUAKEWORLD

				other.modelindex = modelindex_eyes;

			#endif // QUAKEWORLD



				other.invisible_time = 1;

				other.invisible_finished = time + 30;

			}

			else if (items_ == IT_SUIT)

			{

				other.rad_time = 1;

				other.radsuit_finished = time + 30;

			}

			else if (items_ == IT_INVULNERABILITY)

			{

				other.invincible_time = 1;

				other.invincible_finished = time + 30;



			#ifdef QUAKE

				other.effects = other.aiment.effects = other.effects | EF_DIMLIGHT_RED;

			#endif // QUAKE



			#ifdef QUAKEWORLD

				other.effects = other.effects | EF_DIMLIGHT_RED;

			#endif // QUAKEWORLD

			}

			else if (items_ == IT_QUAD)

			{

				other.super_time = 1;

				other.super_damage_finished = time + 30;



			#ifdef QUAKE

				other.effects = other.aiment.effects = other.effects | EF_DIMLIGHT_BLUE;

			#endif // QUAKE



			#ifdef QUAKEWORLD

				other.effects = other.effects | EF_DIMLIGHT_BLUE;

			#endif // QUAKEWORLD

			}



			other.items = other.items | items_;



			UpdateGoalEntity();

		}

	}

};





/*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32)

Player is invulnerable for 30 seconds

*/

void() item_artifact_invulnerability =

{

	if (game_disable_powerups)

		self.flags = self.flags | FL_REMOVE;



	self.touch = powerup_touch;

	precache_model ("progs/invulner.mdl");

	self.noise = "items/protect.wav";

	setmodel (self, "progs/invulner.mdl");

	self.netname = "Pentagram of Protection";

//#ifdef QUAKEWORLD

	self.effects = self.effects | EF_RED;

//#endif // QUAKEWORLD

	self.items = IT_INVULNERABILITY;

	setsize (self, '-16 -16 -24', '16 16 32');

	self.aflag = 300;

	self.desire = goal_NULL;

	StartItem ();

};



void() lose_artifact_invulnerability =

{

	self.items = self.items & IT_NOT_INVULNERABILITY;

	self.invincible_time = 0;

	self.invincible_finished = 0;

	if (!self.super_damage_finished)

	if (!(self.player_flag & ITEM_ENEMY_FLAG))

	{

	#ifdef QUAKE

		self.effects = self.aiment.effects = self.effects & NOT_EF_DIMLIGHT;

	#endif // QUAKE



	#ifdef QUAKEWORLD

		self.effects = self.effects & NOT_EF_DIMLIGHT;

	#endif // QUAKEWORLD

	}

#ifdef QUAKE

	self.effects = self.aiment.effects = self.effects & NOT_EF_RED;

#endif // QUAKE





#ifdef QUAKEWORLD

	self.effects = self.effects & NOT_EF_RED;

#endif // QUAKEWORLD



};





void() item_artifact_super_damage =

{

	if (game_disable_powerups)

		self.flags = self.flags | FL_REMOVE;



	self.touch = powerup_touch;

	precache_model ("progs/quaddama.mdl");

	precache_sound ("items/damage.wav");

	precache_sound ("items/damage2.wav");

	precache_sound ("items/damage3.wav");

	self.noise = "items/damage.wav";

	setmodel (self, "progs/quaddama.mdl");

	if (quad_factor == 4)

		self.netname = "Quad Damage";

	else

		self.netname = "OctaPower";



//#ifdef QUAKEWORLD

	self.effects = self.effects | EF_BLUE;

//#endif // QUAKEWORLD

	self.items = IT_QUAD;

	setsize (self, '-16 -16 -24', '16 16 32');

	self.aflag = 60;

	self.desire = goal_artifact_super_damage;

	StartItem ();

};



void() lose_artifact_super_damage =

{

	self.items = self.items & IT_NOT_QUAD;

	self.super_damage_finished = 0;

	self.super_time = 0;

	if (!self.invincible_finished)











	if (!(self.player_flag & ITEM_ENEMY_FLAG))

	{

	#ifdef QUAKE

		self.effects = self.aiment.effects = self.effects & NOT_EF_DIMLIGHT;

	#endif // QUAKE



	#ifdef QUAKEWORLD

		self.effects = self.effects & NOT_EF_DIMLIGHT;

	#endif // QUAKEWORLD

	}

#ifdef QUAKE

	self.effects = self.aiment.effects = self.effects & NOT_EF_BLUE;

#endif // QUAKE



#ifdef QUAKEWORLD

	self.effects = self.effects & NOT_EF_BLUE;

#endif // QUAKEWORLD

};

Now enjoy a proper blue/red quad/pent. Now why didnt iD do this for quake? [Ed: regular quake development was stopped short :( ]


 
Not logged in
Sign up
Login:
Passwd: