Main  |  Maps  |  Programming | Links |  Files |  Demos |  Forums

This tut shows you how to add a new award that you receive for hitting and killing a person in air. Note this is based on the 1.17 source code! This might
have to be changed for the 1.2x source code! Also you will need this file. Get it here. You might have to right-click->Save As.

First off go to bg_public.h and find:

#define	EF_MOVER_STOP		0x00000400		// will push otherwise

Directly up underneath add:

#define	EF_AWARD_AIRKILL	0x00000800		// draw an airkill sprite

That lets it know when we get the award so it can add it on top of our head.

Now find:

// reward sounds
 typedef enum {
 	REWARD_BAD,
 
 	REWARD_IMPRESSIVE,

Now directly under that add:

	REWARD_AIRKILL,

That of course defines to play the sound, now find this tidbit of code:

	// these were added for single player awards tracking
 	PERS_IMPRESSIVE_COUNT,

Now guess what we add? This of course:

	PERS_AIRKILL_COUNT,

That tells how many of these awards you have that are Air Kills.

Now open cg_local.h and find:

   qhandle_t	medalImpressive;

Up under it add:

	qhandle_t	medalAirKill;

That gives us a place so we can store a reference to the sprite we use that goes over your head.
Now we need to make a place to store the sound path, find:

	sfxHandle_t impressiveSound;

Below it add:

	sfxHandle_t airkillSound;

Now open up cg_main.c and find:

	cgs.media.impressiveSound = trap_S_RegisterSound( "sound/feedback/impressive.wav" );

Below it add:

	cgs.media.airkillSound = trap_S_RegisterSound( "sound/feedback/airkill.wav" );

That says what to play when we receive the award.
Now we gotta declare the path for the shader/sprite that appears over your head, so go find:

	cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" );

Below it add:

	cgs.media.medalAirKill = trap_R_RegisterShaderNoMip( "medal_airkill" );

Now we gotta go and open up cg_players.c and tell it to draw the award abover our head when we receive it. Find:

    if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) {
 		CG_PlayerFloatSprite( cent, cgs.media.medalImpressive );
 		return;
 	}

Up under it add:

    if ( cent->currentState.eFlags & EF_AWARD_AIRKILL ) {
 		CG_PlayerFloatSprite( cent, cgs.media.medalAirKill );
 		return;
 	}

Now open up cg_playerstate.c and find:

		case REWARD_IMPRESSIVE:
 			trap_S_StartLocalSound( cgs.media.impressiveSound, CHAN_ANNOUNCER );
 			cg.rewardTime = cg.time;
 			cg.rewardShader = cgs.media.medalImpressive;
 			cg.rewardCount = ps->persistant[PERS_IMPRESSIVE_COUNT];
 			break;

Now lets add below that:

		case REWARD_AIRKILL:
 			trap_S_StartLocalSound( cgs.media.airkillSound, CHAN_ANNOUNCER );
 			cg.rewardTime = cg.time;
 			cg.rewardShader = cgs.media.medalAirKill;
 			cg.rewardCount = ps->persistant[PERS_AIRKILL_COUNT];
 			break;

That starts up the predfined sound, tells it what shader to use as the image over our head, and then sets the rewardCount to how many of these we hav received( not sure of its purpose ).
Now open up g_active.c and find this:

// clear the rewards if time

And replace that and the function below it with:

	// clear the rewards if time
 	if ( level.time > client->rewardTime ) {
 		client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_AIRKILL |
                 EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );
 	}

That just takes away the award when ready.
Open up g_arenas.c and find a line that starts out like this:

		Com_sprintf( msg, sizeof(msg), "postgame

And replace the function with:

		Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i",
 level.numNonSpectatorClients, playerClientNum, accuracy, player->client->ps.persistant[PERS_IMPRESSIVE_COUNT],
 player->client->ps.persistant[PERS_AIRKILL_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
 player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE], perfect );

Now open up g_combat.c and find this bit of code:

	if (attacker && attacker->client) {
 		if ( attacker == self || OnSameTeam (self, attacker ) ) {
 			AddScore( attacker, -1 );
 		} else {

And replace that and the large chunk of code following it with:

	if (attacker && attacker->client) {
 		if ( attacker == self || OnSameTeam (self, attacker ) ) {
 			AddScore( attacker, -1 );
 		} else {
 			AddScore( attacker, 1 );
 
 			if( meansOfDeath == MOD_GAUNTLET ) {
 				attacker->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
 				attacker->client->ps.persistant[PERS_REWARD] = REWARD_GAUNTLET;
 				attacker->client->ps.persistant[PERS_REWARD_COUNT]++;
 
 				// add the sprite over the player's head
 				attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE |
                                 EF_AWARD_AIRKILL | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );
 				attacker->client->ps.eFlags |= EF_AWARD_GAUNTLET;
 				attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
 
 				// also play humiliation on target
 				self->client->ps.persistant[PERS_REWARD] = REWARD_GAUNTLET;
 				self->client->ps.persistant[PERS_REWARD_COUNT]++;
 			}
             // check for airkill
 			// FireWorks!
 			if ( self->s.groundEntityNum == ENTITYNUM_NONE ) {
 			attacker->client->ps.persistant[PERS_REWARD_COUNT]++;
 			attacker->client->ps.persistant[PERS_REWARD] = REWARD_AIRKILL;
 			attacker->client->ps.persistant[PERS_AIRKILL_COUNT]++;
 			// add the sprite over the player's head
 			attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE |
                         EF_AWARD_AIRKILL | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );
 			attacker->client->ps.eFlags |= EF_AWARD_AIRKILL;
 			attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
 			}
 			// check for two kills in a short amount of time
 			// if this is close enough to the last kill, give a reward sound
 			if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
 				attacker->client->ps.persistant[PERS_REWARD_COUNT]++;
 				attacker->client->ps.persistant[PERS_REWARD] = REWARD_EXCELLENT;
 				attacker->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
 
 				// add the sprite over the player's head
 				attacker->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE |
                                 EF_AWARD_AIRKILL | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );
 				attacker->client->ps.eFlags |= EF_AWARD_EXCELLENT;
 				attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME;
 			}
 			attacker->client->lastKillTime = level.time;
 
 		}
 	} else {
 		AddScore( self, -1 );
 	}

Now, the final step! Open up g_weapon.c and find:

			// add the sprite over the player's head

And replace the next line with:

			ent->client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_AIRKILL |
 EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET );

There, we are done! Compile all 3 projects and enjoy!

I spend my time programming and writing these tutorials, so please feel free to use this code in your mod as long as www.inolen.com and the author receive credit.

Design Copyright inolen 2000