Changes for Cgame Module Files
In cg_local.h before the struct centity_s definition about line 163 add :
#ifdef SINGLEPLAYER // npc
#define MAX_SOUNDS_NPC 10
typedef struct npcSounds_s {
int count;
int frame[MAX_SOUNDS_NPC];
sfxHandle_t sound[MAX_SOUNDS_NPC];
} npcSounds_t;
typedef struct {
lerpFrame_t body;
int sound;
} npcEntity_t;
#endif
In cg_local.h in the struct centity_s definition about line 197 add :
playerEntity_t pe;
#ifdef SINGLEPLAYER // npc
npcEntity_t ne;
#endif
int errorTime; // decay the error from this time
vec3_t errorOrigin;
vec3_t errorAngles;
In cg_local.h after the struct weaponInfo_s definition about line 434 add :
} weaponInfo_t;
#ifdef SINGLEPLAYER // npc
//
// Each NPC in the Game has an associated npcInfo_t;
//
typedef struct {
qboolean registered;
qhandle_t model;
animation_t animations[MAX_TOTALANIMATIONS];
npcSounds_t sounds[MAX_ANIMATIONS_NPC];
} npcInfo_t;
#endif
In cg_local.h about line 1045 add :
sfxHandle_t wstbimpdSound;
sfxHandle_t wstbactvSound;
#ifdef SINGLEPLAYER // npc
sfxHandle_t hulkQuakeSound;
#endif
} cgMedia_t;
In cg_local.h about line 1147 add :
extern weaponInfo_t cg_weapons[MAX_WEAPONS];
extern itemInfo_t cg_items[MAX_ITEMS];
#ifdef SINGLEPLAYER // npc
extern npcInfo_t cg_npcs[NPC_NUMNPCS];
#endif
extern markPoly_t cg_markPolys[MAX_MARK_POLYS];
In cg_local.h about line 1406 add :
void CG_NewClientInfo( int clientNum );
sfxHandle_t CG_CustomSound( int clientNum, const char *soundName );
#ifdef SINGLEPLAYER // npc
void CG_RunLerpFrameNPC( animation_t *ai, lerpFrame_t *lf, int newAnimation, float speedScale );
#endif
In cg_local.h about line 1518 add :
localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
qhandle_t hModel, qhandle_t shader, int msec,
qboolean isSprite );
#ifdef SINGLEPLAYER // npc
void CG_Earthquake();
void CG_StartEarthquake(int intensity,int duration);
#endif
In cg_local.h about line 1566 add :
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops );
void CG_CheckChangedPredictableEvents( playerState_t *ps );
#ifdef SINGLEPLAYER // npc
//
// cg_npcs.c
//
void CG_NPC( centity_t *cent );
void CG_RegisterNPCVisuals( int itemNum );
#endif
In cg_draw.c in function CG_DrawActive about line 2737 add :
if ( separation != 0 ) {
VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg );
}
#ifdef SINGLEPLAYER // npc
CG_Earthquake();
#endif
// draw 3D view
trap_R_RenderScene( &cg.refdef );
In cg_effects.c at the end of the file add :
#ifdef SINGLEPLAYER // npc
int flagEarthquake=qfalse;
int earthquakeIntensity=0;
int earthquakeStoptime=0;
void CG_StartEarthquake(int intensity,int duration)
{
flagEarthquake=qtrue;
if (intensity<earthquakeIntensity) return;
earthquakeIntensity=intensity;
earthquakeStoptime=cg.time+duration;
}
void CG_Earthquake()
{
static float terremotoX,terremotoY,terremotoZ;
static terremotoTime=0;
float realInt;
if (!flagEarthquake) return;
if (earthquakeStoptime<cg.time)
{
flagEarthquake=qfalse;
earthquakeIntensity=0;
return;
}
if (terremotoTime<cg.time)
{
terremotoTime=cg.time+=50;
realInt=((float)earthquakeIntensity+1.0)/2.0;
terremotoX=random()*realInt-realInt/2;
terremotoY=random()*realInt-realInt/2;
terremotoZ=random()*realInt-realInt/2;
}
cg.refdefViewAngles[0]+=terremotoX;
cg.refdefViewAngles[1]+=terremotoY;
cg.refdefViewAngles[2]+=terremotoZ;
AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );
}
#endif
In cg_ents.c in function CG_AddCEntity about line 952 add :
case ET_GENERAL:
CG_General( cent );
break;
#ifdef SINGLEPLAYER // npc
case ET_NPC:
CG_NPC( cent );
break;
#endif
case ET_PLAYER:
CG_Player( cent );
break;
In cg_event.c in function CG_EntityEvent about line 815 add :
case EV_USE_ITEM14:
DEBUGNAME("EV_USE_ITEM14");
CG_UseItem( cent );
break;
#ifdef SINGLEPLAYER // npc
case EV_EARTHQUAKE:
if ((es->eventParm & 0xFF) == 0xFF)
{
CG_StartEarthquake(5,HULK_QUAKE_LEN); // HULK attack
trap_S_StartSound(NULL,0,CHAN_AUTO,cgs.media.hulkQuakeSound);
}
else if ((es->eventParm & 0xFF) == 0xFE)
{
CG_StartEarthquake(4,100);
}
else if ((es->eventParm & 0xFF) == 0xFE)
{
CG_StartEarthquake(3,500); // Sealord earthquake
}
else
CG_StartEarthquake( es->eventParm&0x0F,
(1 + ((es->eventParm&0xF0)>>4))*2000);
break;
#endif
In cg_main.c about line 91 add :
weaponInfo_t cg_weapons[MAX_WEAPONS];
itemInfo_t cg_items[MAX_ITEMS];
#ifdef SINGLEPLAYER // npc
npcInfo_t cg_npcs[NPC_NUMNPCS];
#endif
In cg_main.c at the end of function CG_RegisterSounds about line 905 add :
#ifdef SINGLEPLAYER // npc
cgs.media.hulkQuakeSound = trap_S_RegisterSound("sound/npc/hulk/hulk_quake.wav",qfalse);
#endif
}
In cg_main.c in function CG_RegisterGraphics about line 923 add :
static void CG_RegisterGraphics( void ) {
int i;
char items[MAX_ITEMS+1];
#ifdef SINGLEPLAYER // npc
char npcs[NPC_NUMNPCS+1];
#endif
static char *sb_nums[11] = {
In cg_main.c in function CG_RegisterGraphics about line 1158 add :
for ( i = 1 ; i < bg_numItems ; i++ ) {
if ( items[ i ] == '1' || cg_buildScript.integer ) {
CG_LoadingItem( i );
CG_RegisterItemVisuals( i );
}
}
#ifdef SINGLEPLAYER // npc
// only register the NPC that the server says we need
Q_strncpyz(npcs, CG_ConfigString( CS_NPCS), sizeof(npcs));
for ( i = 0 ; i < NPC_NUMNPCS ; i++ ) {
if ( npcs[ i ] == '1' || cg_buildScript.integer ) {
CG_RegisterNPCVisuals( i );
}
}
#endif
// wall marks
cgs.media.bulletMarkShader = trap_R_RegisterShader( "gfx/damage/bullet_mrk" );
cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burn_med_mrk" );
In cg_main.c in function CG_Init about line 2268 add :
memset( cg_weapons, 0, sizeof(cg_weapons) );
memset( cg_items, 0, sizeof(cg_items) );
#ifdef SINGLEPLAYER // npc
memset( cg_npcs, 0, sizeof(cg_npcs) );
#endif
In cg_players.c just before function CG_RunLerpFrame about line 1119 add :
#ifdef SINGLEPLAYER // npc
static void CG_SetLerpFrameAnimationNPC( animation_t *ai, lerpFrame_t *lf, int newAnimation ) {
animation_t *anim;
lf->animationNumber = newAnimation;
newAnimation &= ~ANIM_TOGGLEBIT;
if ( newAnimation < 0 || newAnimation >= MAX_TOTALANIMATIONS ) {
CG_Error( "Bad animation number: %i", newAnimation );
}
anim = ai+newAnimation;
lf->animation = anim;
lf->animationTime = lf->frameTime + anim->initialLerp;
if ( cg_debugAnim.integer ) {
CG_Printf( "Anim: %i\n", newAnimation );
}
}
/*
===============
CG_RunLerpFrameNPC
Sets cg.snap, cg.oldFrame, and cg.backlerp
cg.time should be between oldFrameTime and frameTime after exit
===============
*/
void CG_RunLerpFrameNPC( animation_t *ai, lerpFrame_t *lf, int newAnimation, float speedScale ) {
int f,numFrames;
animation_t *anim;
// debugging tool to get no animations
if ( cg_animSpeed.integer == 0 ) {
lf->oldFrame = lf->frame = lf->backlerp = 0;
return;
}
// see if the animation sequence is switching
if ( newAnimation != lf->animationNumber || !lf->animation ) {
CG_SetLerpFrameAnimationNPC( ai, lf, newAnimation );
}
// if we have passed the current frame, move it to
// oldFrame and calculate a new frame
if ( cg.time >= lf->frameTime ) {
lf->oldFrame = lf->frame;
lf->oldFrameTime = lf->frameTime;
// get the next frame based on the animation
anim = lf->animation;
if ( !anim->frameLerp ) {
return; // shouldn't happen
}
if ( cg.time < lf->animationTime ) {
lf->frameTime = lf->animationTime; // initial lerp
} else {
lf->frameTime = lf->oldFrameTime + anim->frameLerp;
}
f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
f *= speedScale; // adjust for haste, etc
numFrames = anim->numFrames;
if (anim->flipflop) {
numFrames *= 2;
}
if ( f >= numFrames ) {
f -= numFrames;
if ( anim->loopFrames ) {
f %= anim->loopFrames;
f += anim->numFrames - anim->loopFrames;
} else {
f = numFrames - 1;
// the animation is stuck at the end, so it
// can immediately transition to another sequence
lf->frameTime = cg.time;
}
}
if ( anim->reversed ) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
}
else if (anim->flipflop && f>=anim->numFrames) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
}
else {
lf->frame = anim->firstFrame + f;
}
if ( cg.time > lf->frameTime ) {
lf->frameTime = cg.time;
if ( cg_debugAnim.integer ) {
CG_Printf( "Clamp lf->frameTime\n");
}
}
}
if ( lf->frameTime > cg.time + 200 ) {
lf->frameTime = cg.time;
}
if ( lf->oldFrameTime > cg.time ) {
lf->oldFrameTime = cg.time;
}
// calculate current lerp value
if ( lf->frameTime == lf->oldFrameTime ) {
lf->backlerp = 0;
} else {
lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime );
}
}
#endif
In cg_weapons.c in function CG_MissileHitWall about line 1871 add :
case WP_ROCKET_LAUNCHER:
#ifdef SINGLEPLAYER // npc
case WP_FIREBALL:
#endif
mod = cgs.media.dishFlashModel;
shader = cgs.media.rocketExplosionShader;
In cg_weapons.c in function CG_MissileHitPlayer about line 2013 add :
case WP_GRENADE_LAUNCHER:
case WP_ROCKET_LAUNCHER:
#ifdef SINGLEPLAYER // npc
case WP_FIREBALL:
#endif
In cg_weapons.c in function CG_ShotgunPellet about line 2071 add :
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return;
}
#ifndef SINGLEPLAYER // npc
if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER ) {
CG_MissileHitPlayer( WP_SHOTGUN, tr.endpos, tr.plane.normal, tr.entityNum );
#else
if ( cg_entities[tr.entityNum].currentState.eType == ET_PLAYER
|| cg_entities[tr.entityNum].currentState.eType == ET_NPC) {
CG_Bleed( tr.endpos, tr.entityNum );
#endif
} else {
if ( tr.surfaceFlags & SURF_NOIMPACT ) {