I lu of trying to expain how it is done i am just going post the code and you can read the notes in it.
/*
=============
CG_AddPlayerWeapon
Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL)
The main player will have this called for BOTH cases, so effects like light and
sound should only be done on the world model case.
=============
*/
void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) {
refEntity_t gun;
refEntity_t barrel;
refEntity_t flash;
vec3_t angles;
weapon_t weaponNum;
weaponInfo_t *weapon;
centity_t *nonPredictedCent;
// q3app (moved *ci up here)
clientInfo_t *ci;
float temp_fl;
ci = &cgs.clientinfo[ cent->currentState.clientNum ];
// --
weaponNum = cent->currentState.weapon;
CG_RegisterWeapon( weaponNum );
weapon = &cg_weapons[weaponNum];
// add the weapon
memset( &gun, 0, sizeof( gun ) );
VectorCopy( parent->lightingOrigin, gun.lightingOrigin );
gun.shadowPlane = parent->shadowPlane;
gun.renderfx = parent->renderfx;
// set custom shading for railgun refire rate
if ( ps ) {
if ( cg.predictedPlayerState.weapon == WP_RAILGUN
&& cg.predictedPlayerState.weaponstate == WEAPON_FIRING ) {
// q3app (won't need f anymore)
// float f;
// f = (float)cg.predictedPlayerState.weaponTime / 1500;
// q3app (railgun shader now glows with effects color and goes white when charged)
gun.shaderRGBA[0] = 255 * ci->color[0];
gun.shaderRGBA[1] = 255 * ci->color[1];
gun.shaderRGBA[2] = 255 * ci->color[2];
gun.shaderRGBA[3] = 255;
// --
} else {
gun.shaderRGBA[0] = 255;
gun.shaderRGBA[1] = 255;
gun.shaderRGBA[2] = 255;
gun.shaderRGBA[3] = 255;
}
}
gun.hModel = weapon->weaponModel;
if (!gun.hModel) {
return;
}
if ( !ps ) {
// add weapon ready sound
cent->pe.lightningFiring = qfalse;
if ( ( cent->currentState.eFlags & EF_FIRING ) && weapon->firingSound ) {
// lightning gun and guantlet make a different sound when fire is held down
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->firingSound );
cent->pe.lightningFiring = qtrue;
} else if ( weapon->readySound ) {
trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound );
}
// q3app (railgun color)
if ( cent->currentState.weapon == WP_RAILGUN ) {
if ( cent->muzzleFlashTime + 1500 > cg.time ) {
gun.shaderRGBA[0] = 255 * ci->color[0];
gun.shaderRGBA[1] = 255 * ci->color[1];
gun.shaderRGBA[2] = 255 * ci->color[2];
gun.shaderRGBA[3] = 255;
} else {
gun.shaderRGBA[0] = 255;
gun.shaderRGBA[1] = 255;
gun.shaderRGBA[2] = 255;
gun.shaderRGBA[3] = 255;
}
}
// --
}
CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon");
CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups );
// add the spinning barrel
if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_GAUNTLET || weaponNum == WP_BFG ) {
memset( &barrel, 0, sizeof( barrel ) );
VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
barrel.shadowPlane = parent->shadowPlane;
barrel.renderfx = parent->renderfx;
barrel.hModel = weapon->barrelModel;
angles[YAW] = 0;
angles[PITCH] = 0;
angles[ROLL] = CG_MachinegunSpinAngle( cent );
AnglesToAxis( angles, barrel.axis );
CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" );
CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups );
}
// make sure we aren't looking at cg.predictedPlayerEntity for LG
nonPredictedCent = &cg_entities[cent->currentState.clientNum];
// if the index of the nonPredictedCent is not the same as the clientNum
// then this is a fake player (like on teh single player podiums), so
// go ahead and use the cent
if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) {
nonPredictedCent = cent;
}
// add the flash
if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK )
&& ( nonPredictedCent->currentState.eFlags & EF_FIRING ) )
{
// continuous flash
} else {
// impulse flash
if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) {
return;
}
}
memset( &flash, 0, sizeof( flash ) );
VectorCopy( parent->lightingOrigin, flash.lightingOrigin );
flash.shadowPlane = parent->shadowPlane;
flash.renderfx = parent->renderfx;
flash.hModel = weapon->flashModel;
if (!flash.hModel) {
return;
}
angles[YAW] = 0;
angles[PITCH] = 0;
angles[ROLL] = crandom() * 10;
AnglesToAxis( angles, flash.axis );
// colorize the railgun blast
if ( weaponNum == WP_RAILGUN ) {
// q3app (*ci moved up to start of function because it's used earlier)
// clientInfo_t *ci;
flash.shaderRGBA[0] = 255 * ci->color[0];
flash.shaderRGBA[1] = 255 * ci->color[1];
flash.shaderRGBA[2] = 255 * ci->color[2];
}
// q3app (flash size)
temp_fl = cgv.cg_gun.flash;
if ( temp_fl > 2 ) {
temp_fl = 2;
}
VectorScale(flash.axis[0], temp_fl, flash.axis[0]);
VectorScale(flash.axis[1], temp_fl, flash.axis[1]);
VectorScale(flash.axis[2], temp_fl, flash.axis[2]);
CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash");
if ( temp_fl > 0 ) { // no drawing of flash if flash size == 0
trap_R_AddRefEntityToScene( &flash );
}
if ( ps || cg.renderingThirdPerson ||
cent->currentState.number != cg.predictedPlayerState.clientNum ) {
// add lightning bolt
CG_LightningBolt( nonPredictedCent, flash.origin );
// add rail trail
CG_SpawnRailTrail( cent, flash.origin );
// make a dlight for the flash
if ( weapon->flashDlightColor[0] || weapon->flashDlightColor[1] || weapon->flashDlightColor[2] ) {
trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), weapon->flashDlightColor[0],
weapon->flashDlightColor[1], weapon->flashDlightColor[2] );
}
}
}
Credit for the edited code go to Dan 'Neurobasher'
Gomes and it can be found in the Quake 3 Arena ++ source.
The site should still be up at http://www.planetquake.com/q3app/
I will allso put a copy of the source in the source archive.
Well enjoy
--powerr