static qboolean CG_CheckCanPlaySound (const vec3_t origin, int entityNum, sfxHandle_t sfx) { if (cg_cpmaSound.integer > 1 || (cg_cpmaSound.integer && cgs.cpma)) { vec3_t ourOrigin; vec3_t soundOrigin; if (wolfcam_following) { VectorCopy(cg_entities[wcg.clientNum].currentState.pos.trBase, ourOrigin); } else { VectorCopy(cg.snap->ps.origin, ourOrigin); } if (origin != NULL && entityNum != 0) { //Com_Printf("^3cpma sound check: origin != null and entityNum %d\n", entityNum); } if (origin == NULL) { if (entityNum == ENTITYNUM_WORLD) { Com_Printf("^3WARNING cpma sound WORLD entity and null origin\n"); return qtrue; } if (entityNum < 0 || entityNum >= MAX_GENTITIES) { Com_Printf("^3WARNING cpma sound invalid entityNum: %d\n", entityNum); return qtrue; } VectorCopy(cg_entities[entityNum].currentState.pos.trBase, soundOrigin); } else { VectorCopy(origin, soundOrigin); } //FIXME check cpma mvd coach if (Distance(ourOrigin, soundOrigin) > 1280.0f) { if (cg_cpmaSound.integer > 2) { CG_Printf("^4cpma sound: skipping, too far %d\n", sfx); trap_S_PrintSfxFilename(sfx); } return qfalse; } if (!trap_R_inPVS(ourOrigin, soundOrigin)) { if (cg_cpmaSound.integer > 2) { CG_Printf("^4cpma sound: skipping, not in pvs %d\n", sfx); trap_S_PrintSfxFilename(sfx); } return qfalse; } //Com_Printf("^5yes... playing ent %d at origin %f %f %f dist^7: %f\n", entityNum, soundOrigin[0], soundOrigin[1], soundOrigin[2], Distance(ourOrigin, soundOrigin)); return qtrue; } else if ((cg_soundPvs.integer == 1 && cgs.realProtocol >= 91) || cg_soundPvs.integer > 1) { // ql spec demos send entity info that isn't in pvs //FIXME duplicate code with cpma sound vec3_t ourOrigin; vec3_t soundOrigin; if (wolfcam_following) { VectorCopy(cg_entities[wcg.clientNum].currentState.pos.trBase, ourOrigin); } else { VectorCopy(cg.snap->ps.origin, ourOrigin); } if (origin != NULL && entityNum != 0) { //Com_Printf("^3sound check: origin != null and entityNum %d\n", entityNum); } if (origin == NULL) { if (entityNum == ENTITYNUM_WORLD) { Com_Printf("^3WARNING sound WORLD entity and null origin\n"); return qtrue; } if (entityNum < 0 || entityNum >= MAX_GENTITIES) { Com_Printf("^3WARNING sound invalid entityNum: %d\n", entityNum); return qtrue; } VectorCopy(cg_entities[entityNum].currentState.pos.trBase, soundOrigin); } else { VectorCopy(origin, soundOrigin); } if (!trap_R_inPVS(ourOrigin, soundOrigin)) { if (cg_soundPvs.integer > 2) { CG_Printf("^4sound: skipping, not in pvs %d\n", sfx); trap_S_PrintSfxFilename(sfx); } return qfalse; } } return qtrue; }
/* =============== CG_AttachmentPoint Return the attachment point =============== */ qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v ) { centity_t *cent; if( !a ) return qfalse; // if it all breaks, then use the last point we know was correct VectorCopy( a->lastValidAttachmentPoint, v ); switch( a->type ) { case AT_STATIC: if( !a->staticValid ) return qfalse; VectorCopy( a->origin, v ); break; case AT_TAG: if( !a->tagValid ) return qfalse; AxisCopy( axisDefault, a->re.axis ); CG_PositionRotatedEntityOnTag( &a->re, &a->parent, a->model, a->tagName ); VectorCopy( a->re.origin, v ); break; case AT_CENT: if( !a->centValid ) return qfalse; if( a->centNum == cg.predictedPlayerState.clientNum ) { // this is smoother if it's the local client VectorCopy( cg.predictedPlayerState.origin, v ); } else { cent = &cg_entities[ a->centNum ]; VectorCopy( cent->lerpOrigin, v ); } break; case AT_PARTICLE: if( !a->particleValid ) return qfalse; if( !a->particle->valid ) { a->particleValid = qfalse; return qfalse; } else VectorCopy( a->particle->origin, v ); break; default: CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); break; } if( a->hasOffset ) VectorAdd( v, a->offset, v ); VectorCopy( v, a->lastValidAttachmentPoint ); return qtrue; }
/* =============== CG_BuildableAnimation =============== */ static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *backLerp ) { entityState_t *es = ¢->currentState; //if no animation is set default to idle anim if( cent->buildableAnim == BANIM_NONE ) { cent->buildableAnim = es->torsoAnim; cent->buildableIdleAnim = qtrue; } //display the first frame of the construction anim if not yet spawned if( !( es->eFlags & EF_B_SPAWNED ) ) { animation_t *anim = &cg_buildables[ es->modelindex ].animations[ BANIM_CONSTRUCT1 ]; //so that when animation starts for real it has sensible numbers cent->lerpFrame.oldFrameTime = cent->lerpFrame.frameTime = cent->lerpFrame.animationTime = cg.time; *old = cent->lerpFrame.oldFrame = anim->firstFrame; *now = cent->lerpFrame.frame = anim->firstFrame; *backLerp = cent->lerpFrame.backlerp = 0.0f; //ensure that an animation is triggered once the buildable has spawned cent->oldBuildableAnim = BANIM_NONE; } else { if( ( cent->oldBuildableAnim ^ es->legsAnim ) & ANIM_TOGGLEBIT ) { if( cg_debugAnim.integer ) CG_Printf( "%d->%d l:%d t:%d %s(%d)\n", cent->oldBuildableAnim, cent->buildableAnim, es->legsAnim, es->torsoAnim, BG_Buildable( es->modelindex )->humanName, es->number ); if( cent->buildableAnim == es->torsoAnim || es->legsAnim & ANIM_FORCEBIT ) { cent->buildableAnim = cent->oldBuildableAnim = es->legsAnim; cent->buildableIdleAnim = qfalse; } else { cent->buildableAnim = cent->oldBuildableAnim = es->torsoAnim; cent->buildableIdleAnim = qtrue; } } else if( cent->buildableIdleAnim == qtrue && cent->buildableAnim != es->torsoAnim ) { cent->buildableAnim = es->torsoAnim; } CG_RunBuildableLerpFrame( cent ); *old = cent->lerpFrame.oldFrame; *now = cent->lerpFrame.frame; *backLerp = cent->lerpFrame.backlerp; } }
/* =============== CG_RunBuildableLerpFrame Sets cg.snap, cg.oldFrame, and cg.backlerp cg.time should be between oldFrameTime and frameTime after exit =============== */ static void CG_RunBuildableLerpFrame( centity_t *cent ) { int f, numFrames; buildable_t buildable = cent->currentState.modelindex; lerpFrame_t *lf = ¢->lerpFrame; animation_t *anim; buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT ); // 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 ) { if( cg_debugRandom.integer ) CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n", newAnimation, lf->animationNumber, lf->animation ); CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation ); if( !cg_buildables[ buildable ].sounds[ newAnimation ].looped && cg_buildables[ buildable ].sounds[ newAnimation ].enabled ) { if( cg_debugRandom.integer ) CG_Printf( "Sound for animation %d for a %s\n", newAnimation, BG_FindHumanNameForBuildable( buildable ) ); trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, cg_buildables[ buildable ].sounds[ newAnimation ].sound ); } } if( cg_buildables[ buildable ].sounds[ lf->animationNumber ].looped && cg_buildables[ buildable ].sounds[ lf->animationNumber ].enabled ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound ); // 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; 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; cent->buildableAnim = cent->currentState.torsoAnim; } } 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 ); }
void CG_EntityEvent( centity_t *cent, vec3_t position ) { entityState_t *es; int event; vec3_t dir; const char *s; int clientNum; clientInfo_t *ci; es = ¢->currentState; event = es->event & ~EV_EVENT_BITS; if ( cg_debugEvents.integer ) { CG_Printf( "ent:%3i event:%3i ", es->number, event ); } if ( !event ) { DEBUGNAME("ZEROEVENT"); return; } clientNum = es->clientNum; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { clientNum = 0; } ci = &cgs.clientinfo[ clientNum ]; switch ( event ) { // // movement generated events // case EV_FOOTSTEP: DEBUGNAME("EV_FOOTSTEP"); if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ ci->footsteps ][rand()&3] ); } break; case EV_FOOTSTEP_METAL: DEBUGNAME("EV_FOOTSTEP_METAL"); if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); } break; case EV_FOOTSPLASH: DEBUGNAME("EV_FOOTSPLASH"); if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); } break; case EV_FOOTWADE: DEBUGNAME("EV_FOOTWADE"); if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); } break; case EV_SWIM: DEBUGNAME("EV_SWIM"); if (cg_footsteps.integer) { trap_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); } break; case EV_FALL_SHORT: DEBUGNAME("EV_FALL_SHORT"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.landSound ); if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -8; cg.landTime = cg.time; } break; case EV_FALL_MEDIUM: DEBUGNAME("EV_FALL_MEDIUM"); // use normal pain sound trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) ); if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -16; cg.landTime = cg.time; } break; case EV_FALL_FAR: DEBUGNAME("EV_FALL_FAR"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); cent->pe.painTime = cg.time; // don't play a pain sound right after this if ( clientNum == cg.predictedPlayerState.clientNum ) { // smooth landing z changes cg.landChange = -24; cg.landTime = cg.time; } break; case EV_STEP_4: case EV_STEP_8: case EV_STEP_12: case EV_STEP_16: // smooth out step up transitions DEBUGNAME("EV_STEP"); { float oldStep; int delta; int step; if ( clientNum != cg.predictedPlayerState.clientNum ) { break; } // if we are interpolating, we don't need to smooth steps if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) || cg_nopredict.integer || cg_synchronousClients.integer ) { break; } // check for stepping up before a previous step is completed delta = cg.time - cg.stepTime; if (delta < STEP_TIME) { oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME; } else { oldStep = 0; } // add this amount step = 4 * (event - EV_STEP_4 + 1 ); cg.stepChange = oldStep + step; if ( cg.stepChange > MAX_STEP_CHANGE ) { cg.stepChange = MAX_STEP_CHANGE; } cg.stepTime = cg.time; break; } case EV_JUMP_PAD: DEBUGNAME("EV_JUMP_PAD"); // CG_Printf( "EV_JUMP_PAD w/effect #%i\n", es->eventParm ); { vec3_t up = {0, 0, 1}; CG_SmokePuff( cent->lerpOrigin, up, 32, 1, 1, 1, 0.33f, 1000, cg.time, 0, LEF_PUFF_DONT_SCALE, cgs.media.smokePuffShader ); } // boing sound at origin, jump sound on player trap_S_StartSound ( cent->lerpOrigin, -1, CHAN_VOICE, cgs.media.jumpPadSound ); trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); break; case EV_JUMP: DEBUGNAME("EV_JUMP"); trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); break; case EV_TAUNT: DEBUGNAME("EV_TAUNT"); trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) ); break; #ifdef MISSIONPACK case EV_TAUNT_YES: DEBUGNAME("EV_TAUNT_YES"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_YES); break; case EV_TAUNT_NO: DEBUGNAME("EV_TAUNT_NO"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_NO); break; case EV_TAUNT_FOLLOWME: DEBUGNAME("EV_TAUNT_FOLLOWME"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_FOLLOWME); break; case EV_TAUNT_GETFLAG: DEBUGNAME("EV_TAUNT_GETFLAG"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONGETFLAG); break; case EV_TAUNT_GUARDBASE: DEBUGNAME("EV_TAUNT_GUARDBASE"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONDEFENSE); break; case EV_TAUNT_PATROL: DEBUGNAME("EV_TAUNT_PATROL"); CG_VoiceChatLocal(SAY_TEAM, qfalse, es->number, COLOR_CYAN, VOICECHAT_ONPATROL); break; #endif case EV_WATER_TOUCH: DEBUGNAME("EV_WATER_TOUCH"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); break; case EV_WATER_LEAVE: DEBUGNAME("EV_WATER_LEAVE"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); break; case EV_WATER_UNDER: DEBUGNAME("EV_WATER_UNDER"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); break; case EV_WATER_CLEAR: DEBUGNAME("EV_WATER_CLEAR"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) ); break; case EV_ITEM_PICKUP: DEBUGNAME("EV_ITEM_PICKUP"); { gitem_t *item; int index; index = es->eventParm; // player predicted if ( index < 1 || index >= bg_numItems ) { break; } item = &bg_itemlist[ index ]; // powerups and team items will have a separate global sound, this one // will be played at prediction time if ( item->giType == IT_POWERUP || item->giType == IT_TEAM) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.n_healthSound ); } else if (item->giType == IT_PERSISTANT_POWERUP) { #ifdef MISSIONPACK switch (item->giTag ) { case PW_SCOUT: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.scoutSound ); break; case PW_GUARD: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.guardSound ); break; case PW_DOUBLER: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.doublerSound ); break; case PW_AMMOREGEN: trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.ammoregenSound ); break; } #endif } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); } // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { CG_ItemPickup( index ); } } break; case EV_GLOBAL_ITEM_PICKUP: DEBUGNAME("EV_GLOBAL_ITEM_PICKUP"); { gitem_t *item; int index; index = es->eventParm; // player predicted if ( index < 1 || index >= bg_numItems ) { break; } item = &bg_itemlist[ index ]; // powerup pickups are global if( item->pickup_sound ) { trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound, qfalse ) ); } // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { CG_ItemPickup( index ); } } break; // // weapon events // case EV_NOAMMO: DEBUGNAME("EV_NOAMMO"); // trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound ); if ( es->number == cg.snap->ps.clientNum ) { CG_OutOfAmmoChange(); } break; case EV_CHANGE_WEAPON: DEBUGNAME("EV_CHANGE_WEAPON"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); CG_FireWeapon( cent ); break; case EV_USE_ITEM0: DEBUGNAME("EV_USE_ITEM0"); CG_UseItem( cent ); break; case EV_USE_ITEM1: DEBUGNAME("EV_USE_ITEM1"); CG_UseItem( cent ); break; case EV_USE_ITEM2: DEBUGNAME("EV_USE_ITEM2"); CG_UseItem( cent ); break; case EV_USE_ITEM3: DEBUGNAME("EV_USE_ITEM3"); CG_UseItem( cent ); break; case EV_USE_ITEM4: DEBUGNAME("EV_USE_ITEM4"); CG_UseItem( cent ); break; case EV_USE_ITEM5: DEBUGNAME("EV_USE_ITEM5"); CG_UseItem( cent ); break; case EV_USE_ITEM6: DEBUGNAME("EV_USE_ITEM6"); CG_UseItem( cent ); break; case EV_USE_ITEM7: DEBUGNAME("EV_USE_ITEM7"); CG_UseItem( cent ); break; case EV_USE_ITEM8: DEBUGNAME("EV_USE_ITEM8"); CG_UseItem( cent ); break; case EV_USE_ITEM9: DEBUGNAME("EV_USE_ITEM9"); CG_UseItem( cent ); break; case EV_USE_ITEM10: DEBUGNAME("EV_USE_ITEM10"); CG_UseItem( cent ); break; case EV_USE_ITEM11: DEBUGNAME("EV_USE_ITEM11"); CG_UseItem( cent ); break; case EV_USE_ITEM12: DEBUGNAME("EV_USE_ITEM12"); CG_UseItem( cent ); break; case EV_USE_ITEM13: DEBUGNAME("EV_USE_ITEM13"); CG_UseItem( cent ); break; case EV_USE_ITEM14: DEBUGNAME("EV_USE_ITEM14"); CG_UseItem( cent ); break; //================================================================= // // other events // case EV_PLAYER_TELEPORT_IN: DEBUGNAME("EV_PLAYER_TELEPORT_IN"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound ); CG_SpawnEffect( position); break; case EV_PLAYER_TELEPORT_OUT: DEBUGNAME("EV_PLAYER_TELEPORT_OUT"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleOutSound ); CG_SpawnEffect( position); break; case EV_ITEM_POP: DEBUGNAME("EV_ITEM_POP"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound ); break; case EV_ITEM_RESPAWN: DEBUGNAME("EV_ITEM_RESPAWN"); cent->miscTime = cg.time; // scale up from this trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.respawnSound ); break; case EV_GRENADE_BOUNCE: DEBUGNAME("EV_GRENADE_BOUNCE"); if ( rand() & 1 ) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound ); } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound ); } break; #ifdef MISSIONPACK case EV_PROXIMITY_MINE_STICK: DEBUGNAME("EV_PROXIMITY_MINE_STICK"); if( es->eventParm & SURF_FLESH ) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimplSound ); } else if( es->eventParm & SURF_METALSTEPS ) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpmSound ); } else { trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbimpdSound ); } break; case EV_PROXIMITY_MINE_TRIGGER: DEBUGNAME("EV_PROXIMITY_MINE_TRIGGER"); trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.wstbactvSound ); break; case EV_KAMIKAZE: DEBUGNAME("EV_KAMIKAZE"); CG_KamikazeEffect( cent->lerpOrigin ); break; case EV_OBELISKEXPLODE: DEBUGNAME("EV_OBELISKEXPLODE"); CG_ObeliskExplode( cent->lerpOrigin, es->eventParm ); break; case EV_OBELISKPAIN: DEBUGNAME("EV_OBELISKPAIN"); CG_ObeliskPain( cent->lerpOrigin ); break; case EV_INVUL_IMPACT: DEBUGNAME("EV_INVUL_IMPACT"); CG_InvulnerabilityImpact( cent->lerpOrigin, cent->currentState.angles ); break; case EV_JUICED: DEBUGNAME("EV_JUICED"); CG_InvulnerabilityJuiced( cent->lerpOrigin ); break; case EV_LIGHTNINGBOLT: DEBUGNAME("EV_LIGHTNINGBOLT"); CG_LightningBoltBeam(es->origin2, es->pos.trBase); break; #endif case EV_SCOREPLUM: DEBUGNAME("EV_SCOREPLUM"); CG_ScorePlum( cent->currentState.otherEntityNum, cent->lerpOrigin, cent->currentState.time ); break; // // missile impacts // case EV_MISSILE_HIT: DEBUGNAME("EV_MISSILE_HIT"); ByteToDir( es->eventParm, dir ); CG_MissileHitPlayer( es->weapon, position, dir, es->otherEntityNum ); break; case EV_MISSILE_MISS: DEBUGNAME("EV_MISSILE_MISS"); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_DEFAULT ); break; case EV_MISSILE_MISS_METAL: DEBUGNAME("EV_MISSILE_MISS_METAL"); ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, 0, position, dir, IMPACTSOUND_METAL ); break; case EV_RAILTRAIL: DEBUGNAME("EV_RAILTRAIL"); cent->currentState.weapon = WP_RAILGUN; if(es->clientNum == cg.snap->ps.clientNum && !cg.renderingThirdPerson) { if(cg_drawGun.integer == 2) VectorMA(es->origin2, 8, cg.refdef.viewaxis[1], es->origin2); else if(cg_drawGun.integer == 3) VectorMA(es->origin2, 4, cg.refdef.viewaxis[1], es->origin2); } CG_RailTrail(ci, es->origin2, es->pos.trBase); // if the end was on a nomark surface, don't make an explosion if ( es->eventParm != 255 ) { ByteToDir( es->eventParm, dir ); CG_MissileHitWall( es->weapon, es->clientNum, position, dir, IMPACTSOUND_DEFAULT ); } break; case EV_BULLET_HIT_WALL: DEBUGNAME("EV_BULLET_HIT_WALL"); ByteToDir( es->eventParm, dir ); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD ); break; case EV_BULLET_HIT_FLESH: DEBUGNAME("EV_BULLET_HIT_FLESH"); CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm ); break; case EV_SHOTGUN: DEBUGNAME("EV_SHOTGUN"); CG_ShotgunFire( es ); break; case EV_GENERAL_SOUND: DEBUGNAME("EV_GENERAL_SOUND"); if ( cgs.gameSounds[ es->eventParm ] ) { trap_S_StartSound (NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); trap_S_StartSound (NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) ); } break; case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes DEBUGNAME("EV_GLOBAL_SOUND"); if ( cgs.gameSounds[ es->eventParm ] ) { trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); trap_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) ); } break; case EV_GLOBAL_TEAM_SOUND: // play from the player's head so it never diminishes { DEBUGNAME("EV_GLOBAL_TEAM_SOUND"); switch( es->eventParm ) { case GTS_RED_CAPTURE: // CTF: red team captured the blue flag, 1FCTF: red team captured the neutral flag if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) CG_AddBufferedSound( cgs.media.captureYourTeamSound ); else CG_AddBufferedSound( cgs.media.captureOpponentSound ); break; case GTS_BLUE_CAPTURE: // CTF: blue team captured the red flag, 1FCTF: blue team captured the neutral flag if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) CG_AddBufferedSound( cgs.media.captureYourTeamSound ); else CG_AddBufferedSound( cgs.media.captureOpponentSound ); break; case GTS_RED_RETURN: // CTF: blue flag returned, 1FCTF: never used if ( cgs.clientinfo[cg.clientNum].team == TEAM_RED ) CG_AddBufferedSound( cgs.media.returnYourTeamSound ); else CG_AddBufferedSound( cgs.media.returnOpponentSound ); // CG_AddBufferedSound( cgs.media.blueFlagReturnedSound ); break; case GTS_BLUE_RETURN: // CTF red flag returned, 1FCTF: neutral flag returned if ( cgs.clientinfo[cg.clientNum].team == TEAM_BLUE ) CG_AddBufferedSound( cgs.media.returnYourTeamSound ); else CG_AddBufferedSound( cgs.media.returnOpponentSound ); // CG_AddBufferedSound( cgs.media.redFlagReturnedSound ); break; case GTS_RED_TAKEN: // CTF: red team took blue flag, 1FCTF: blue team took the neutral flag // if this player picked up the flag then a sound is played in CG_CheckLocalSounds if (cg.snap->ps.powerups[PW_BLUEFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { } else { if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } break; case GTS_BLUE_TAKEN: // CTF: blue team took the red flag, 1FCTF red team took the neutral flag // if this player picked up the flag then a sound is played in CG_CheckLocalSounds if (cg.snap->ps.powerups[PW_REDFLAG] || cg.snap->ps.powerups[PW_NEUTRALFLAG]) { } else { if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.yourTeamTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.enemyTookYourFlagSound ); } else if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { #ifdef MISSIONPACK if (cgs.gametype == GT_1FCTF) CG_AddBufferedSound( cgs.media.enemyTookTheFlagSound ); else #endif CG_AddBufferedSound( cgs.media.yourTeamTookEnemyFlagSound ); } } break; #ifdef MISSIONPACK case GTS_REDOBELISK_ATTACKED: // Overload: red obelisk is being attacked if (cgs.clientinfo[cg.clientNum].team == TEAM_RED) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; case GTS_BLUEOBELISK_ATTACKED: // Overload: blue obelisk is being attacked if (cgs.clientinfo[cg.clientNum].team == TEAM_BLUE) { CG_AddBufferedSound( cgs.media.yourBaseIsUnderAttackSound ); } break; #endif case GTS_REDTEAM_SCORED: CG_AddBufferedSound(cgs.media.redScoredSound); break; case GTS_BLUETEAM_SCORED: CG_AddBufferedSound(cgs.media.blueScoredSound); break; case GTS_REDTEAM_TOOK_LEAD: CG_AddBufferedSound(cgs.media.redLeadsSound); break; case GTS_BLUETEAM_TOOK_LEAD: CG_AddBufferedSound(cgs.media.blueLeadsSound); break; case GTS_TEAMS_ARE_TIED: CG_AddBufferedSound( cgs.media.teamsTiedSound ); break; #ifdef MISSIONPACK case GTS_KAMIKAZE: trap_S_StartLocalSound(cgs.media.kamikazeFarSound, CHAN_ANNOUNCER); break; #endif default: break; } break; } case EV_PAIN: // local player sounds are triggered in CG_CheckLocalSounds, // so ignore events on the player DEBUGNAME("EV_PAIN"); if ( cent->currentState.number != cg.snap->ps.clientNum ) { CG_PainEvent( cent, es->eventParm ); } break; case EV_DEATH1: case EV_DEATH2: case EV_DEATH3: DEBUGNAME("EV_DEATHx"); if (CG_WaterLevel(cent) >= 1) { trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, "*drown.wav")); } else { trap_S_StartSound(NULL, es->number, CHAN_VOICE, CG_CustomSound(es->number, va("*death%i.wav", event - EV_DEATH1 + 1))); } break; case EV_OBITUARY: DEBUGNAME("EV_OBITUARY"); CG_Obituary( es ); break; // // powerup events // case EV_POWERUP_QUAD: DEBUGNAME("EV_POWERUP_QUAD"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_QUAD; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.quadSound ); break; case EV_POWERUP_BATTLESUIT: DEBUGNAME("EV_POWERUP_BATTLESUIT"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_BATTLESUIT; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.protectSound ); break; case EV_POWERUP_REGEN: DEBUGNAME("EV_POWERUP_REGEN"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_REGEN; cg.powerupTime = cg.time; } trap_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.regenSound ); break; case EV_GIB_PLAYER: DEBUGNAME("EV_GIB_PLAYER"); // don't play gib sound when using the kamikaze because it interferes // with the kamikaze sound, downside is that the gib sound will also // not be played when someone is gibbed while just carrying the kamikaze if ( !(es->eFlags & EF_KAMIKAZE) ) { trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.gibSound ); } CG_GibPlayer( cent->lerpOrigin ); break; case EV_STOPLOOPINGSOUND: DEBUGNAME("EV_STOPLOOPINGSOUND"); trap_S_StopLoopingSound( es->number ); es->loopSound = 0; break; case EV_DEBUG_LINE: DEBUGNAME("EV_DEBUG_LINE"); CG_Beam( cent ); break; default: DEBUGNAME("UNKNOWN"); CG_Error( "Unknown event: %i", event ); break; } }
/* ================= CG_ServerCommand The string has been tokenized and can be retrieved with Cmd_Argc() / Cmd_Argv() ================= */ static void CG_ServerCommand( void ) { const char *cmd; char text[MAX_SAY_TEXT]; cmd = CG_Argv(0); if ( !cmd[0] ) { // server claimed the command return; } if ( !strcmp( cmd, "cp" ) ) { CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); return; } if ( !strcmp( cmd, "cs" ) ) { CG_ConfigStringModified(); return; } if ( !strcmp( cmd, "print" ) ) { CG_Printf( "%s", CG_Argv(1) ); #ifdef MISSIONPACK cmd = CG_Argv(1); // yes, this is obviously a hack, but so is the way we hear about // votes passing or failing if ( !Q_stricmpn( cmd, "vote failed", 11 ) || !Q_stricmpn( cmd, "team vote failed", 16 )) { trap_S_StartLocalSound( cgs.media.voteFailed, CHAN_ANNOUNCER ); } else if ( !Q_stricmpn( cmd, "vote passed", 11 ) || !Q_stricmpn( cmd, "team vote passed", 16 ) ) { trap_S_StartLocalSound( cgs.media.votePassed, CHAN_ANNOUNCER ); } #endif return; } if ( !strcmp( cmd, "chat" ) ) { if ( cgs.gametype >= GT_TEAM && cg_teamChatsOnly.integer ) { return; } trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); CG_RemoveChatEscapeChar( text ); CG_Printf( "%s\n", text ); return; } if ( !strcmp( cmd, "tchat" ) ) { trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT ); CG_RemoveChatEscapeChar( text ); CG_AddToTeamChat( text ); CG_Printf( "%s\n", text ); return; } #ifdef MISSIONPACK if ( !strcmp( cmd, "vchat" ) ) { CG_VoiceChat( SAY_ALL ); return; } if ( !strcmp( cmd, "vtchat" ) ) { CG_VoiceChat( SAY_TEAM ); return; } if ( !strcmp( cmd, "vtell" ) ) { CG_VoiceChat( SAY_TELL ); return; } #endif if ( !strcmp( cmd, "scores" ) ) { CG_ParseScores(); return; } if ( !strcmp( cmd, "tinfo" ) ) { CG_ParseTeamInfo(); return; } if ( !strcmp( cmd, "map_restart" ) ) { CG_MapRestart(); return; } if ( Q_stricmp (cmd, "remapShader") == 0 ) { if (trap_Argc() == 4) { char shader1[MAX_QPATH]; char shader2[MAX_QPATH]; char shader3[MAX_QPATH]; Q_strncpyz(shader1, CG_Argv(1), sizeof(shader1)); Q_strncpyz(shader2, CG_Argv(2), sizeof(shader2)); Q_strncpyz(shader3, CG_Argv(3), sizeof(shader3)); trap_R_RemapShader(shader1, shader2, shader3); } return; } // loaddeferred can be both a servercmd and a consolecmd if ( !strcmp( cmd, "loaddefered" ) ) { // FIXME: spelled wrong, but not changing for demo CG_LoadDeferredPlayers(); return; } // clientLevelShot is sent before taking a special screenshot for // the menu system during development if ( !strcmp( cmd, "clientLevelShot" ) ) { cg.levelShot = qtrue; return; } CG_Printf( "Unknown client game command: %s\n", cmd ); }
/* ============= CG_Viewpos_f Debugging command to print the current position ============= */ static void CG_Viewpos_f (void) { CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0], (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], (int)cg.refdefViewAngles[YAW]); }
void CG_AddPMItem(popupMessageType_t type, const char *message, qhandle_t shader) { pmListItem_t *listItem; char *end; if(!message || !*message) { return; } if((unsigned)type >= PM_NUM_TYPES) { CG_Printf("Invalid popup type: %d\n", type); return; } listItem = CG_FindFreePMItem(); if(!listItem) { return; } if(shader) { listItem->shader = shader; } else { listItem->shader = cgs.media.pmImages[type]; } listItem->inuse = qtrue; listItem->type = type; Q_strncpyz(listItem->message, message, sizeof(cg_pmStack[0].message)); // rain - moved this: print and THEN chop off the newline, as the // console deals with newlines perfectly. We do chop off the newline // at the end, if any, though. if(listItem->message[strlen(listItem->message) - 1] == '\n') { listItem->message[strlen(listItem->message) - 1] = 0; } trap_Print(va("%s\n", listItem->message)); // rain - added parens while((end = strchr(listItem->message, '\n'))) { *end = '\0'; } // rain - don't eat popups for empty lines if(*listItem->message == '\0') { return; } if(!cg_pmWaitingList) { cg_pmWaitingList = listItem; listItem->time = cg.time; } else { pmListItem_t *loop = cg_pmWaitingList; while(loop->next) { loop = loop->next; } loop->next = listItem; } }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; cg.cld = 0; // NERVE - SMF - reset clientDamage #ifdef DEBUGTIME_ENABLED int dbgTime = trap_Milliseconds(),elapsed; int dbgCnt = 0; #endif cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); /* // RF, if we should force a weapon, then do so if( !cg.weaponSelect ) { if (cg_loadWeaponSelect.integer > 0) { cg.weaponSelect = cg_loadWeaponSelect.integer; cg.weaponSelectTime = cg.time; trap_Cvar_Set( "cg_loadWeaponSelect", "0" ); // turn it off } } */ #ifdef DEBUGTIME_ENABLED CG_Printf( "\n" ); #endif DEBUGTIME // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds( qfalse ); DEBUGTIME // clear all the render lists trap_R_ClearScene(); DEBUGTIME // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); DEBUGTIME // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } if ( cg.weaponSelect == WP_FG42SCOPE || cg.weaponSelect == WP_SNOOPERSCOPE || cg.weaponSelect == WP_SNIPERRIFLE ) { float spd; spd = VectorLength( cg.snap->ps.velocity ); if ( spd > 180.0f ) { switch ( cg.weaponSelect ) { case WP_FG42SCOPE: CG_FinishWeaponChange( cg.weaponSelect, WP_FG42 ); break; case WP_SNOOPERSCOPE: CG_FinishWeaponChange( cg.weaponSelect, WP_GARAND ); break; case WP_SNIPERRIFLE: CG_FinishWeaponChange( cg.weaponSelect, WP_MAUSER ); break; } } } DEBUGTIME if ( !cg.lightstylesInited ) { CG_SetupDlightstyles(); } DEBUGTIME // if we have been told not to render, don't if ( cg_norender.integer ) { return; } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); DEBUGTIME // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer /*|| (cg.snap->ps.stats[STAT_HEALTH] <= 0)*/; // build cg.refdef inwater = CG_CalcViewValues(); CG_CalcShakeCamera(); CG_ApplyShakeCamera(); DEBUGTIME // RF, draw the skyboxportal CG_DrawSkyBoxPortal(); DEBUGTIME if ( inwater ) { CG_UnderwaterSounds(); } DEBUGTIME // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { CG_DamageBlendBlob(); } DEBUGTIME // build the render lists if ( !cg.hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); DEBUGTIME // Rafael particles CG_AddParticles(); // done. DEBUGTIME CG_AddLocalEntities(); DEBUGTIME }
/* ====================== CG_AddParticles ====================== */ void CG_ParticleSnowFlurry (qhandle_t pshader, centity_t *cent) { cparticle_t *p; qboolean turb = qtrue; if (!pshader) CG_Printf ("CG_ParticleSnowFlurry pshader == ZERO!\n"); if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cg.time; p->color = 0; p->alpha = 0.90f; p->alphavel = 0; p->start = cent->currentState.origin2[0]; p->end = cent->currentState.origin2[1]; p->endtime = cg.time + cent->currentState.time; p->startfade = cg.time + cent->currentState.time2; p->pshader = pshader; if (rand()%100 > 90) { p->height = 32; p->width = 32; p->alpha = 0.10f; } else { p->height = 1; p->width = 1; } p->vel[2] = -20; p->type = P_WEATHER_FLURRY; if (turb) p->vel[2] = -10; VectorCopy(cent->currentState.origin, p->org); p->org[0] = p->org[0]; p->org[1] = p->org[1]; p->org[2] = p->org[2]; p->vel[0] = p->vel[1] = 0; p->accel[0] = p->accel[1] = p->accel[2] = 0; p->vel[0] += cent->currentState.angles[0] * 32 + (crandom() * 16); p->vel[1] += cent->currentState.angles[1] * 32 + (crandom() * 16); p->vel[2] += cent->currentState.angles[2]; if (turb) { p->accel[0] = crandom () * 16; p->accel[1] = crandom () * 16; } }
void CG_EffectParse(const char *effectstr) { // Split the string into it's component parts. float bmin, bmax, cmin, cmax, gmin, gmax, bdrop, gdrop /*, wsplash, lsplash*/; int count, bheight; char *startptr, *eqptr, *endptr; char workbuff[128]; atmFXType_t atmFXType = ATM_NONE; if (CG_AtmosphericKludge()) { return; } // Set up some default values cg_atmFx.baseVec[0] = cg_atmFx.baseVec[1] = 0; cg_atmFx.gustVec[0] = cg_atmFx.gustVec[1] = 100; bmin = 5; bmax = 10; cmin = 1; cmax = 1; gmin = 0; gmax = 2; bdrop = gdrop = 300; cg_atmFx.baseWeight = 0.7f; cg_atmFx.gustWeight = 1.5f; bheight = 0; // Parse the parameter string Q_strncpyz(workbuff, effectstr, sizeof(workbuff)); for (startptr = workbuff; *startptr; ) { for (eqptr = startptr; *eqptr && *eqptr != '=' && *eqptr != ','; eqptr++) ; if (!*eqptr) { break; // No more string } if (*eqptr == ',') { startptr = eqptr + 1; // Bad argument, continue continue; } *eqptr++ = 0; for (endptr = eqptr; *endptr && *endptr != ','; endptr++) ; if (*endptr) { *endptr++ = 0; } if (atmFXType == ATM_NONE) { if (Q_stricmp(startptr, "T")) { cg_atmFx.numDrops = 0; CG_Printf("Atmospheric effect must start with a type.\n"); return; } if (!Q_stricmp(eqptr, "RAIN")) { atmFXType = ATM_RAIN; cg_atmFx.ParticleCheckVisible = &CG_RainParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_RainParticleGenerate; cg_atmFx.ParticleRender = &CG_RainParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_RAIN_SPEED; } else if (!Q_stricmp(eqptr, "SNOW")) { atmFXType = ATM_SNOW; cg_atmFx.ParticleCheckVisible = &CG_SnowParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_SnowParticleGenerate; cg_atmFx.ParticleRender = &CG_SnowParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_SNOW_SPEED; } else { cg_atmFx.numDrops = 0; CG_Printf("Only effect type 'rain' and 'snow' are supported.\n"); return; } } else { if (!Q_stricmp(startptr, "B")) { CG_EP_ParseFloats(eqptr, &bmin, &bmax); } else if (!Q_stricmp(startptr, "C")) { CG_EP_ParseFloats(eqptr, &cmin, &cmax); } else if (!Q_stricmp(startptr, "G")) { CG_EP_ParseFloats(eqptr, &gmin, &gmax); } else if (!Q_stricmp(startptr, "BV")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.baseVec[0], &cg_atmFx.baseVec[1]); } else if (!Q_stricmp(startptr, "GV")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.gustVec[0], &cg_atmFx.gustVec[1]); } else if (!Q_stricmp(startptr, "W")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.baseWeight, &cg_atmFx.gustWeight); } else if (!Q_stricmp(startptr, "D")) { CG_EP_ParseFloats(eqptr, &bdrop, &gdrop); } else if (!Q_stricmp(startptr, "H")) { CG_EP_ParseInts(eqptr, &bheight, &bheight); } else { CG_Printf("Unknown effect key '%s'.\n", startptr); } } startptr = endptr; } if (atmFXType == ATM_NONE || !BG_LoadTraceMap(cgs.rawmapname, cg.mapcoordsMins, cg.mapcoordsMaxs)) { // No effects cg_atmFx.numDrops = -1; return; } cg_atmFx.baseHeightOffset = bheight; if (cg_atmFx.baseHeightOffset < 0) { cg_atmFx.baseHeightOffset = 0; } cg_atmFx.baseMinTime = 1000 * bmin; cg_atmFx.baseMaxTime = 1000 * bmax; cg_atmFx.changeMinTime = 1000 * cmin; cg_atmFx.changeMaxTime = 1000 * cmax; cg_atmFx.gustMinTime = 1000 * gmin; cg_atmFx.gustMaxTime = 1000 * gmax; cg_atmFx.baseDrops = bdrop; cg_atmFx.gustDrops = gdrop; cg_atmFx.numDrops = (cg_atmFx.baseDrops > cg_atmFx.gustDrops) ? cg_atmFx.baseDrops : cg_atmFx.gustDrops; if (cg_atmFx.numDrops > MAX_ATMOSPHERIC_PARTICLES) { cg_atmFx.numDrops = MAX_ATMOSPHERIC_PARTICLES; } // Load graphics if (atmFXType == ATM_RAIN) // Rain { cg_atmFx.numEffectShaders = 1; cg_atmFx.effectshaders[0] = trap_R_RegisterShader("gfx/misc/raindrop"); if (!(cg_atmFx.effectshaders[0])) { cg_atmFx.effectshaders[0] = -1; cg_atmFx.numEffectShaders = 0; } } else if (atmFXType == ATM_SNOW) // Snow { cg_atmFx.numEffectShaders = 1; cg_atmFx.effectshaders[0] = trap_R_RegisterShader("gfx/misc/snow"); // This really should never happen } else { cg_atmFx.numEffectShaders = 0; } // Initialise atmospheric effect to prevent all particles falling at the start for (count = 0; count < cg_atmFx.numDrops; count++) { cg_atmFx.particles[count].nextDropTime = ATMOSPHERIC_DROPDELAY + (rand() % ATMOSPHERIC_DROPDELAY); } CG_EffectGust(); }
void CG_Particle_OilSlick (qhandle_t pshader, centity_t *cent) { cparticle_t *p; if (!pshader) CG_Printf ("CG_Particle_OilSlick == ZERO!\n"); if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cg.time; if (cent->currentState.angles2[2]) p->endtime = cg.time + cent->currentState.angles2[2]; else p->endtime = cg.time + 60000; p->startfade = p->endtime; p->alpha = 1.0; p->alphavel = 0; p->roll = 0; p->pshader = pshader; if (cent->currentState.angles2[0] || cent->currentState.angles2[1]) { p->width = cent->currentState.angles2[0]; p->height = cent->currentState.angles2[0]; p->endheight = cent->currentState.angles2[1]; p->endwidth = cent->currentState.angles2[1]; } else { p->width = 8; p->height = 8; p->endheight = 16; p->endwidth = 16; } p->type = P_FLAT_SCALEUP; p->snum = 1.0; VectorCopy(cent->currentState.origin, p->org ); p->org[2]+= 0.55 + (crandom() * 0.5); p->vel[0] = 0; p->vel[1] = 0; p->vel[2] = 0; VectorClear( p->accel ); p->rotate = qfalse; p->roll = rand()%179; p->alpha = 0.75; }
void CG_Particle_OilParticle (qhandle_t pshader, centity_t *cent) { cparticle_t *p; int time; int time2; float ratio; float duration = 1500; time = cg.time; time2 = cg.time + cent->currentState.time; ratio =(float)1 - ((float)time / (float)time2); if (!pshader) CG_Printf ("CG_Particle_OilParticle == ZERO!\n"); if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cg.time; p->alpha = 1.0; p->alphavel = 0; p->roll = 0; p->pshader = pshader; p->endtime = cg.time + duration; p->startfade = p->endtime; p->width = 1; p->height = 3; p->endheight = 3; p->endwidth = 1; p->type = P_SMOKE; VectorCopy(cent->currentState.origin, p->org ); p->vel[0] = (cent->currentState.origin2[0] * (16 * ratio)); p->vel[1] = (cent->currentState.origin2[1] * (16 * ratio)); p->vel[2] = (cent->currentState.origin2[2]); p->snum = 1.0f; VectorClear( p->accel ); p->accel[2] = -20; p->rotate = qfalse; p->roll = rand()%179; p->alpha = 0.75; }
/* ================= CG_RegisterGraphics This function may execute for a couple of minutes with a slow disk. ================= */ static void CG_RegisterGraphics( void ) { int i; const char *str; // clear any references to old media memset( &cg.refdef, 0, sizeof( cg.refdef ) ); trap_R_ClearScene(); CG_LoadingString( cgs.mapname ); trap_R_LoadWorldMap( cgs.mapname ); // precache status bar pics CG_LoadingString( "game media" ); cgs.media.crosshairShader[0] = trap_R_RegisterShader( "gfx/2d/BLANK" ); cgs.media.crosshairShader[1] = trap_R_RegisterShader( "textures/hud/crosshair" ); cgs.media.crosshairShader[2] = trap_R_RegisterShader( "gfx/2d/crosshair" ); cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" ); cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" ); cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" ); // su44: MoHAA zoom overlays cgs.media.zoomOverlayShader = trap_R_RegisterShader("textures/hud/zoomoverlay"); cgs.media.kar98TopOverlayShader = trap_R_RegisterShader("textures/hud/kartop.tga"); cgs.media.kar98BottomOverlayShader = trap_R_RegisterShader("textures/hud/karbottom.tga"); cgs.media.binocularsOverlayShader = trap_R_RegisterShader("textures/hud/binocularsoverlay"); // register the inline models cgs.numInlineModels = trap_CM_NumInlineModels(); for ( i = 1 ; i < cgs.numInlineModels ; i++ ) { char name[10]; vec3_t mins, maxs; int j; Com_sprintf( name, sizeof(name), "*%i", i ); cgs.inlineDrawModel[i] = trap_R_RegisterModel( name ); trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs ); for ( j = 0 ; j < 3 ; j++ ) { cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] ); } } // register all the server specified models for (i=1 ; i<MAX_MODELS ; i++) { const char *modelName; modelName = CG_ConfigString( CS_MODELS+i ); if ( !modelName[0] ) { break; } cgs.gameModels[i] = trap_R_RegisterModel( modelName ); if( modelName[0] != '*') { cgs.gameTIKIs[i] = trap_TIKI_RegisterModel( modelName ); if(cgs.gameTIKIs[i] == 0) { CG_Printf("CG_RegisterGraphics: failed to load tiki file %s (%i)\n",modelName,i); } } } for (i=0; i<64; i++) { const char *itemName; itemName = CG_ConfigString( CS_WEAPONS+i ); if(itemName[0]) { CG_RegisterItemName(i, itemName); } } for( i = CS_RAIN_DENSITY; i != (CS_RAIN_NUMSHADERS+1); i++) { str = CG_ConfigString( i ); CG_RainCSUpdated(i,str); } str = CG_ConfigString( CS_FOGINFO ); sscanf(str, "%d %f %f %f %f", &cg.farplane_cull, &cg.farplane_distance, &cg.farplane_color[0], &cg.farplane_color[1], &cg.farplane_color[2]); CG_ClearParticles (); }
/* =============== CG_AttachmentDir Return the attachment direction =============== */ bool CG_AttachmentDir( attachment_t *a, vec3_t v ) { vec3_t forward; centity_t *cent; if ( !a ) { return false; } switch ( a->type ) { case AT_STATIC: return false; case AT_TAG: if ( !a->tagValid ) { return false; } VectorCopy( a->re.axis[ 0 ], v ); break; case AT_CENT: if ( !a->centValid ) { return false; } cent = &cg_entities[ a->centNum ]; AngleVectors( cent->lerpAngles, forward, nullptr, nullptr ); VectorCopy( forward, v ); break; case AT_PARTICLE: if ( !a->particleValid ) { return false; } if ( !a->particle->valid ) { a->particleValid = false; return false; } else { VectorCopy( a->particle->velocity, v ); } break; default: CG_Printf( S_ERROR "Invalid attachmentType_t in attachment\n" ); break; } VectorNormalize( v ); return true; }
void CG_DrawGameText(void) { if ( !cg.gameTextTime ) { return; } CG_Printf("CG_DrawGameText() being called. Tell Ste\n"); /* char *start; int l; int i,max; int x, y; char linebuffer[1024], string[1024]; int holdCnt; vec4_t color; // Advance to next line (if there are any) and calculate time to show if ( cg.gameNextTextTime < cg.time ) { cg.gameTextCurrentLine += MAX_NUM_GAMELINES; if (cg.gameTextCurrentLine >= cg.scrollTextLines) { cg.gameTextTime = 0; return; } else { max = MAX_NUM_GAMELINES; if ((cg.scrollTextLines - cg.gameTextCurrentLine) < max) { max = cg.scrollTextLines - cg.gameTextCurrentLine; } // Loop through next lines to calc how long to show 'em holdCnt = 0; for (i=cg.gameTextCurrentLine;i<(cg.gameTextCurrentLine + max);++i) { holdCnt += strlen(cg.printText[i]); } cg.gameNextTextTime = cg.time + (holdCnt * cg.gameLetterTime); } } // Give a color if one wasn't given if((textcolor_caption[0] == 0) && (textcolor_caption[1] == 0) && (textcolor_caption[2] == 0) && (textcolor_caption[3] == 0)) { Vector4Copy( colorTable[CT_WHITE], textcolor_caption ); } color[0] = colorTable[CT_BLACK][0]; color[1] = colorTable[CT_BLACK][1]; color[2] = colorTable[CT_BLACK][2]; color[3] = 0.350f; // Set Y of the first line y = cg.printTextY; x = GAMETEXT_X_START; // Background cgi_R_SetColor(color); // Background, CLAMP TO 4 LINES CG_DrawPic( x - 4, y - SMALLCHAR_HEIGHT - 2, (70 * SMALLCHAR_WIDTH),(( ((cg.scrollTextLines>MAX_NUM_GAMELINES)?MAX_NUM_GAMELINES:cg.scrollTextLines) + 1) * SMALLCHAR_HEIGHT) + 4, cgs.media.ammoslider ); sprintf(string, "%s:", speakerTable[cg.gameTextSpeaker].stringID); CG_DrawStringExt( x, y - SMALLCHAR_HEIGHT, string, colorTable[CT_LTPURPLE1], qfalse, qtrue, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT ); for (i= cg.gameTextCurrentLine;i< cg.gameTextCurrentLine + MAX_NUM_GAMELINES;++i) { start = cg.printText[i]; while ( 1 ) { for ( l = 0; l < 80; l++ ) { if ( !start[l] || start[l] == '\n' ) { break; } linebuffer[l] = start[l]; } linebuffer[l] = 0; CG_DrawStringExt( x, y, linebuffer, textcolor_caption, qfalse, qtrue, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT ); y += SMALLCHAR_HEIGHT; while ( *start && ( *start != '\n' ) ) { start++; } if ( !*start ) { break; } start++; } } cgi_R_SetColor( NULL ); */ }
void CG_AddPMItem(popupMessageType_t type, const char *message, const char *message2, qhandle_t shader, qhandle_t weaponShader, int scaleShader, vec3_t color) { pmListItem_t *listItem; char *end; if (!message || !*message) { return; } if (type >= PM_NUM_TYPES) { CG_Printf("Invalid popup type: %d\n", type); return; } listItem = CG_FindFreePMItem(); if (!listItem) { return; } if (shader) { listItem->shader = shader; } else { listItem->shader = -1; } if (message2) { listItem->weaponShader = weaponShader; listItem->scaleShader = scaleShader; } else { listItem->weaponShader = -1; } // colored obituaries listItem->color[0] = listItem->color[1] = listItem->color[2] = 1.f; if (color != NULL) { VectorCopy(color, listItem->color); } listItem->inuse = qtrue; listItem->type = type; Q_strncpyz(listItem->message, message, sizeof(cg_pmStack[0].message)); // print and THEN chop off the newline, as the console deals with newlines perfectly if (listItem->message[strlen(listItem->message) - 1] == '\n') { listItem->message[strlen(listItem->message) - 1] = 0; } // chop off the newline at the end if any while ((end = strchr(listItem->message, '\n'))) { *end = '\0'; } // don't eat popups for empty lines if (*listItem->message == '\0') { return; } if (message2) { Q_strncpyz(listItem->message2, message2, sizeof(cg_pmStack[0].message2)); if (listItem->message[strlen(listItem->message2) - 1] == '\n') { listItem->message[strlen(listItem->message2) - 1] = 0; } while ((end = strchr(listItem->message2, '\n'))) { *end = '\0'; } if (*listItem->message2 == '\0') { return; } } if (!cg_pmWaitingList) { cg_pmWaitingList = listItem; listItem->time = cg.time; } else { pmListItem_t *loop = cg_pmWaitingList; while (loop->next) { loop = loop->next; } loop->next = listItem; } }
void CG_GameText(int y ) { CG_Printf("CG_GameText() being called. Tell Ste\n"); /* const char *s,*holds; int i, len; float x, w; int numChars; int text_i; char str[MAX_QPATH]; int holdCnt,playingTime; int totalLength,sound,max; Q_strncpyz (str, CG_Argv( 1 ), MAX_QPATH ); cg.gameTextSpeaker = atoi(CG_Argv(2)); cg.gameTextEntNum = atoi(CG_Argv(3)); sound = cgs.sound_precache[atoi(CG_Argv(4))]; text_i = CG_SearchTextPrecache(str); //ensure we found a match if (text_i == -1) { Com_Printf("WARNING: CG_GameText given invalid text key :'%s'",str); return; } cg.gameTextTime = cg.time; cg.printTextY = 5 + SMALLCHAR_HEIGHT; cg.gameTextCurrentLine = 0; // count the number of lines for centering cg.scrollTextLines = 1; memset (cg.printText, 0, sizeof(cg.printText)); // Break into individual lines i = 0; len = 0; s = precacheText[text_i].text; holds = s; playingTime = cgi_S_GetSampleLength(sound); totalLength = strlen(s); if (totalLength == 0) { totalLength = 1; } cg.gameLetterTime = playingTime / totalLength; //We start at column 75 according to DrawGameText x = GAMETEXT_X_START; w = GAMETEXT_X_END - GAMETEXT_X_START; numChars = floor(w/SMALLCHAR_WIDTH); while( *s ) { len++; if (*s == '\n') {//Being told explicitly to start a new line Q_strncpyz( cg.printText[i], holds, len); i++; len = 0; holds = s; holds++; cg.scrollTextLines++; } else if ( len == numChars ) {//Reached max length of this line //step back until we find a space while( len && *s != ' ' ) { s--; len--; } //break the line here Q_strncpyz( cg.printText[i], holds, len); i++; len = 0; holds = s; holds++; cg.scrollTextLines++; } s++; } len++; // So the NULL will be properly placed at the end of the string of Q_strncpyz Q_strncpyz( cg.printText[i], holds, len); // To get the last line //NOTE: This might be able to use the VoiceVolume or TID_VOICE info from the cg.gameTextEntNum // to decide when to drop the text... max = MAX_NUM_GAMELINES; if (max >cg.scrollTextLines) { max = cg.scrollTextLines; } holdCnt = 0; for (i=0;i<max;++i) { holdCnt += strlen(cg.printText[i]); } cg.gameNextTextTime = cg.time + (holdCnt * cg.gameLetterTime); cg.scrollTextTime = 0; // No scrolling during captions */ }
/* ======================== CG_ReadNextSnapshot This is the only place new snapshots are requested This may increment cgs.processedSnapshotNum multiple times if the client system fails to return a valid snapshot. ======================== */ static snapshot_t *CG_ReadNextSnapshot( void ) { qboolean r; snapshot_t *dest; if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) { CG_Printf( "[skipnotify]WARNING: CG_ReadNextSnapshot: way out of range, %i > %i\n", cg.latestSnapshotNum, cgs.processedSnapshotNum ); } while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) { // decide which of the two slots to load it into if ( cg.snap == &cg.activeSnapshots[0] ) { dest = &cg.activeSnapshots[1]; } else { dest = &cg.activeSnapshots[0]; } // try to read the snapshot from the client system cgs.processedSnapshotNum++; r = trap_GetSnapshot( cgs.processedSnapshotNum, dest ); // FIXME: why would trap_GetSnapshot return a snapshot with the same server time if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) { //continue; } // if it succeeded, return if ( r ) { CG_AddLagometerSnapshotInfo( dest ); // server has been restarted if ( cg.snap && ( dest->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) { cg.damageTime = 0; cg.duckTime = -1; cg.landTime = -1; cg.stepTime = -1; #ifdef SAVEGAME_SUPPORT // savegame: we should use this as our new base snapshot if( CG_IsSinglePlayer() ) { int i; centity_t backupCent; CG_SetInitialSnapshot( dest ); cg.nextFrameTeleport = qtrue; // loadgame hasn't occured yet, so this is likely wrong //cg.weaponSelect = cg.snap->ps.weapon; cg.weaponSelectTime = cg.time; memset( cg.viewDamage, 0, sizeof(cg.viewDamage) ); // memset( cg.cameraShake, 0, sizeof(cg.cameraShake) ); // go through an reset the cent's for (i=0; i<MAX_GENTITIES; i++) { backupCent = cg_entities[i]; memset( &cg_entities[i], 0, sizeof(centity_t) ); cg_entities[i].currentState = backupCent.currentState; cg_entities[i].nextState = backupCent.nextState; cg_entities[i].currentValid = backupCent.currentValid; cg_entities[i].interpolate = backupCent.interpolate; } // reset the predicted cent memset( &cg.predictedPlayerEntity, 0, sizeof(centity_t) ); cg.predictedPlayerEntity.currentState = backupCent.currentState; cg.predictedPlayerEntity.nextState = backupCent.nextState; cg.predictedPlayerEntity.currentValid = backupCent.currentValid; cg.predictedPlayerEntity.interpolate = backupCent.interpolate; return NULL; } #endif // SAVEGAME_SUPPORT } // return dest; } // a GetSnapshot will return failure if the snapshot // never arrived, or is so old that its entities // have been shoved off the end of the circular // buffer in the client system. // record as a dropped packet CG_AddLagometerSnapshotInfo( NULL ); // If there are additional snapshots, continue trying to // read them. } // nothing left to read return NULL; }
/* ================== CG_EventHandling ================== */ void CG_EventHandling( int type, qboolean fForced ) { CG_Printf("EventHandling: %d\n", type); if( cg.demoPlayback && type == CGAME_EVENT_NONE && !fForced ) { type = CGAME_EVENT_DEMO; } if( type != CGAME_EVENT_NONE ) { trap_Cvar_Set( "cl_bypassMouseInput", 0 ); } switch( type ) { // OSP - Demo support case CGAME_EVENT_DEMO: cgs.fResize = qfalse; cgs.fSelect = qfalse; cgs.cursorUpdate = cg.time + 10000; cgs.timescaleUpdate = cg.time + 4000; CG_ScoresUp_f(); break; case CGAME_EVENT_SPEAKEREDITOR: case CGAME_EVENT_GAMEVIEW: case CGAME_EVENT_NONE: case CGAME_EVENT_CAMPAIGNBREIFING: case CGAME_EVENT_FIRETEAMMSG: case CGAME_EVENT_MULTIVIEW: default: // default handling (cleanup mostly) if( cgs.eventHandling == CGAME_EVENT_HUDEDITOR) { // forty - visual hud editor cg.hudEditor.showHudEditor = qfalse; } else if(cgs.eventHandling == CGAME_EVENT_MULTIVIEW) { if( type == -CGAME_EVENT_MULTIVIEW) { type = CGAME_EVENT_NONE; } else { trap_Key_SetCatcher( KEYCATCH_CGAME ); return; } } else if( cgs.eventHandling == CGAME_EVENT_GAMEVIEW ) { cg.showGameView = qfalse; trap_S_FadeBackgroundTrack( 0.0f, 500, 0 ); trap_S_StopStreamingSound( -1 ); cg.limboEndCinematicTime = 0; if( fForced ) { if( cgs.limboLoadoutModified ) { trap_SendClientCommand( "rs" ); cgs.limboLoadoutSelected = qfalse; } } } else if( cgs.eventHandling == CGAME_EVENT_SPEAKEREDITOR ) { if( type == -CGAME_EVENT_SPEAKEREDITOR ) { type = CGAME_EVENT_NONE; } else { trap_Key_SetCatcher( KEYCATCH_CGAME ); return; } } else if( cgs.eventHandling == CGAME_EVENT_CAMPAIGNBREIFING ) { type = CGAME_EVENT_GAMEVIEW; } else if( cgs.eventHandling == CGAME_EVENT_FIRETEAMMSG ) { cg.showFireteamMenu = qfalse; trap_Cvar_Set( "cl_bypassmouseinput", "0" ); } else if( cg.snap && cg.snap->ps.pm_type == PM_INTERMISSION && fForced ) { trap_UI_Popup( UIMENU_INGAME ); } break; } cgs.eventHandling = type; if(type == CGAME_EVENT_NONE) { trap_Key_SetCatcher(trap_Key_GetCatcher() & ~KEYCATCH_CGAME); ccInitial = qfalse; if(cg.demoPlayback && cg.demohelpWindow != SHOW_OFF) { CG_ShowHelp_Off(&cg.demohelpWindow); } } else if( type == CGAME_EVENT_HUDEDITOR ) { // forty - visual hud editor cg.hudEditor.showHudEditor = qtrue; trap_Key_SetCatcher(KEYCATCH_CGAME); } else if( type == CGAME_EVENT_MULTIVIEW ) { trap_Key_SetCatcher(KEYCATCH_CGAME); } else if( type == CGAME_EVENT_GAMEVIEW ) { cg.showGameView = qtrue; CG_LimboPanel_Setup(); trap_Key_SetCatcher(KEYCATCH_CGAME); } else if( type == CGAME_EVENT_FIRETEAMMSG ) { cgs.ftMenuPos = -1; cgs.ftMenuMode = 0; cg.showFireteamMenu = qtrue; trap_Cvar_Set( "cl_bypassmouseinput", "1" ); trap_Key_SetCatcher(KEYCATCH_CGAME); } else { trap_Key_SetCatcher(KEYCATCH_CGAME); } }
qboolean CG_LuaStartVM(lvm_t * vm) { int res = 0; char homepath[MAX_QPATH], gamepath[MAX_QPATH]; vm->L = luaL_newstate(); if(!vm->L) { LUA_LOG("Lua: Lua failed to initialise.\n"); return qfalse; } luaL_openlibs(vm->L); trap_Cvar_VariableStringBuffer("fs_homepath", homepath, sizeof(homepath)); trap_Cvar_VariableStringBuffer("fs_game", gamepath, sizeof(gamepath)); lua_getglobal(vm->L, LUA_LOADLIBNAME); if(lua_istable(vm->L, -1)) { lua_pushstring(vm->L, va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); lua_setfield(vm->L, -2, "path"); lua_pushstring(vm->L, va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); lua_setfield(vm->L, -2, "cpath"); } lua_pop(vm->L, 1); Lua_RegisterGlobal(vm->L, "LUA_PATH", va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP)); Lua_RegisterGlobal(vm->L, "LUA_CPATH", va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s", homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION, homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION)); Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP); lua_newtable(vm->L); Lua_RegConstInteger(vm->L, CS_PLAYERS); Lua_RegConstInteger(vm->L, EXEC_NOW); Lua_RegConstInteger(vm->L, EXEC_INSERT); Lua_RegConstInteger(vm->L, EXEC_APPEND); Lua_RegConstInteger(vm->L, FS_READ); Lua_RegConstInteger(vm->L, FS_WRITE); Lua_RegConstInteger(vm->L, FS_APPEND); Lua_RegConstInteger(vm->L, FS_APPEND_SYNC); Lua_RegConstInteger(vm->L, SAY_ALL); Lua_RegConstInteger(vm->L, SAY_TEAM); Lua_RegConstString(vm->L, HOSTARCH); luaopen_base(vm->L); luaopen_string(vm->L); luaopen_coroutine(vm->L); Luaopen_Qmath(vm->L); Luaopen_Vector(vm->L); res = luaL_loadbuffer(vm->L, vm->code, vm->code_size, vm->filename); if(res == LUA_ERRSYNTAX) { LUA_LOG("Lua: syntax error during pre-compilation: %s\n", (char *)lua_tostring(vm->L, -1)); CG_Printf(S_COLOR_YELLOW "Lua: syntax error: %s\n", (char *)lua_tostring(vm->L, -1)); lua_pop(vm->L, 1); vm->error++; return qfalse; } else if(res == LUA_ERRMEM) { LUA_LOG("Lua: memory allocation error #1 ( %s )\n", vm->filename); vm->error++; return qfalse; } if(!CG_LuaCall(vm, "CG_LuaStartVM", 0, 0)) return qfalse; LUA_LOG("Lua: Loading %s\n", vm->filename); return qtrue; }
void CG_EntityEvent( centity_t *cent, vec3_t position ) { entityState_t *es; int event; vec3_t axis[3]; const char *s, *s2; int clientNum; //clientInfo_t *ci; es = ¢->currentState; event = es->event & ~EV_EVENT_BITS; if ( cg_debugEvents.integer ) { CG_Printf( "ent:%3i event:%3i ", es->number, event ); } if ( !event ) { DEBUGNAME("ZEROEVENT"); return; } if ( !cent->gent )//|| !cent->gent->client ) { return; } //ci = ¢->gent->client->clientInfo; clientNum = cent->gent->s.number; switch ( event ) { // // movement generated events // case EV_FOOTSTEP: DEBUGNAME("EV_FOOTSTEP"); if (cg_footsteps.integer) { if ( cent->gent && cent->gent->s.number == 0 && !cg.renderingThirdPerson )//!cg_thirdPerson.integer ) {//Everyone else has keyframed footsteps in animsounds.cfg cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_NORMAL ][rand()&3] ); } } break; case EV_FOOTSTEP_METAL: DEBUGNAME("EV_FOOTSTEP_METAL"); if (cg_footsteps.integer) { if ( cent->gent && cent->gent->s.number == 0 && !cg.renderingThirdPerson )//!cg_thirdPerson.integer ) {//Everyone else has keyframed footsteps in animsounds.cfg cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_METAL ][rand()&3] ); } } break; case EV_FOOTSPLASH: DEBUGNAME("EV_FOOTSPLASH"); if (cg_footsteps.integer) { cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); } break; case EV_FOOTWADE: DEBUGNAME("EV_FOOTWADE"); if (cg_footsteps.integer) { cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_WADE ][rand()&3] ); } break; case EV_SWIM: DEBUGNAME("EV_SWIM"); if (cg_footsteps.integer) { cgi_S_StartSound (NULL, es->number, CHAN_BODY, cgs.media.footsteps[ FOOTSTEP_SWIM ][rand()&3] ); } break; case EV_FALL_SHORT: DEBUGNAME("EV_FALL_SHORT"); cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); if ( clientNum == cg.predicted_player_state.clientNum ) { // smooth landing z changes cg.landChange = -8; cg.landTime = cg.time; } //FIXME: maybe kick up some dust? break; case EV_FALL_MEDIUM: DEBUGNAME("EV_FALL_MEDIUM"); // use normal pain sound - if ( g_entities[es->number].health <= 0 ) {//dead cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); } else if ( g_entities[es->number].s.weapon == WP_SABER ) {//jedi CG_TryPlayCustomSound( NULL, es->number, CHAN_BODY, "*land1.wav", CS_BASIC ); } else {//still alive CG_TryPlayCustomSound( NULL, es->number, CHAN_BODY, "*pain100.wav", CS_BASIC ); } if ( clientNum == cg.predicted_player_state.clientNum ) { // smooth landing z changes cg.landChange = -16; cg.landTime = cg.time; } //FIXME: maybe kick up some dust? break; case EV_FALL_FAR: DEBUGNAME("EV_FALL_FAR"); CG_TryPlayCustomSound( NULL, es->number, CHAN_BODY, "*land1.wav", CS_BASIC ); cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); cent->pe.painTime = cg.time; // don't play a pain sound right after this if ( clientNum == cg.predicted_player_state.clientNum ) { // smooth landing z changes cg.landChange = -24; cg.landTime = cg.time; } //FIXME: maybe kick up some dust? break; case EV_STEP_4: case EV_STEP_8: case EV_STEP_12: case EV_STEP_16: // smooth out step up transitions DEBUGNAME("EV_STEP"); { float oldStep; int delta; int step; if ( clientNum != cg.predicted_player_state.clientNum ) { break; } // if we are interpolating, we don't need to smooth steps if ( cg_timescale.value >= 1.0f ) { break; } // check for stepping up before a previous step is completed delta = cg.time - cg.stepTime; if (delta < STEP_TIME) { oldStep = cg.stepChange * (STEP_TIME - delta) / STEP_TIME; } else { oldStep = 0; } // add this amount step = 4 * (event - EV_STEP_4 + 1 ); cg.stepChange = oldStep + step; if ( cg.stepChange > MAX_STEP_CHANGE ) { cg.stepChange = MAX_STEP_CHANGE; } cg.stepTime = cg.time; break; } case EV_JUMP: DEBUGNAME("EV_JUMP"); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, "*jump1.wav", CS_BASIC );//CHAN_VOICE break; case EV_ROLL: DEBUGNAME("EV_ROLL"); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, "*jump1.wav", CS_BASIC );//CHAN_VOICE cgi_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.rollSound );//CHAN_AUTO //FIXME: need some sort of body impact on ground sound and maybe kick up some dust? break; case EV_WATER_TOUCH: DEBUGNAME("EV_WATER_TOUCH"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); break; case EV_WATER_LEAVE: DEBUGNAME("EV_WATER_LEAVE"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); break; case EV_WATER_UNDER: DEBUGNAME("EV_WATER_UNDER"); cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); break; case EV_WATER_CLEAR: DEBUGNAME("EV_WATER_CLEAR"); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, "*gasp.wav", CS_BASIC ); break; case EV_WATER_GURP1: case EV_WATER_GURP2: DEBUGNAME("EV_WATER_GURPx"); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, va("*gurp%d.wav",event-EV_WATER_GURP1+1), CS_BASIC ); break; case EV_WATER_DROWN: DEBUGNAME("EV_WATER_DROWN"); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, "*drown.wav", CS_BASIC ); break; case EV_ITEM_PICKUP: DEBUGNAME("EV_ITEM_PICKUP"); { gitem_t *item; int index; qboolean bHadItem = qfalse; index = es->eventParm; // player predicted if ( (char)index < 0 ) { index = -(char)index; bHadItem = qtrue; } if ( index >= bg_numItems ) { break; } item = &bg_itemlist[ index ]; cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgi_S_RegisterSound( item->pickup_sound ) ); // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { CG_ItemPickup( index, bHadItem ); } } break; // // weapon events // case EV_NOAMMO: DEBUGNAME("EV_NOAMMO"); //cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.noAmmoSound ); if ( es->number == cg.snap->ps.clientNum ) { CG_OutOfAmmoChange(); } break; case EV_CHANGE_WEAPON: DEBUGNAME("EV_CHANGE_WEAPON"); if ( es->weapon == WP_SABER ) { /* if ( !cent->gent || !cent->gent->client || (cent->currentState.saberInFlight == qfalse && cent->currentState.saberActive == qtrue) ) { cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberoffquick.wav" ) ); } */ if ( cent->gent && cent->gent->client ) { //if ( cent->gent->client->ps.saberInFlight ) {//if it's not in flight or lying around, turn it off! cent->currentState.saberActive = qfalse; } } } // FIXME: if it happens that you don't want the saber to play the switch sounds, feel free to modify this bit. if ( weaponData[cg.weaponSelect].selectSnd[0] ) { // custom select sound cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgi_S_RegisterSound( weaponData[cg.weaponSelect].selectSnd )); } else { // generic sound cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); } break; case EV_FIRE_WEAPON: DEBUGNAME("EV_FIRE_WEAPON"); CG_FireWeapon( cent, qfalse ); break; case EV_ALT_FIRE: DEBUGNAME("EV_ALT_FIRE"); CG_FireWeapon( cent, qtrue ); break; case EV_DISRUPTOR_MAIN_SHOT: DEBUGNAME("EV_DISRUPTOR_MAIN_SHOT"); FX_DisruptorMainShot( cent->currentState.origin2, cent->lerpOrigin ); break; case EV_DISRUPTOR_SNIPER_SHOT: DEBUGNAME("EV_DISRUPTOR_SNIPER_SHOT"); FX_DisruptorAltShot( cent->currentState.origin2, cent->lerpOrigin, cent->gent->alt_fire ); break; case EV_DISRUPTOR_SNIPER_MISS: DEBUGNAME("EV_DISRUPTOR_SNIPER_MISS"); FX_DisruptorAltMiss( cent->lerpOrigin, cent->gent->pos1 ); break; case EV_DEMP2_ALT_IMPACT: FX_DEMP2_AltDetonate( cent->lerpOrigin, es->eventParm ); break; // case EV_POWERUP_SEEKER_FIRE: // DEBUGNAME("EV_POWERUP_SEEKER_FIRE"); // CG_FireSeeker( cent ); // break; case EV_POWERUP_BATTLESUIT: DEBUGNAME("EV_POWERUP_BATTLESUIT"); if ( es->number == cg.snap->ps.clientNum ) { cg.powerupActive = PW_BATTLESUIT; cg.powerupTime = cg.time; } //cgi_S_StartSound (NULL, es->number, CHAN_ITEM, cgs.media.invulnoProtectSound ); break; //================================================================= // // other events // case EV_REPLICATOR: DEBUGNAME("EV_REPLICATOR"); // FX_Replicator( cent, position ); break; case EV_BATTERIES_CHARGED: cg.batteryChargeTime = cg.time + 3000; cgi_S_StartSound( (float*)vec3_origin, es->number, CHAN_AUTO, cgs.media.batteryChargeSound ); break; case EV_DISINTEGRATION: { DEBUGNAME("EV_DISINTEGRATION"); qboolean makeNotSolid = qfalse; int disintPW = es->eventParm; int disintEffect = 0; int disintLength = 0; qhandle_t disintSound1 = NULL; qhandle_t disintSound2 = NULL; qhandle_t disintSound3 = NULL; switch( disintPW ) { case PW_DISRUPTION:// sniper rifle disintEffect = EF_DISINTEGRATION;//ef_ disintSound1 = cgs.media.disintegrateSound;//with scream disintSound2 = cgs.media.disintegrate2Sound;//no scream disintSound3 = cgs.media.disintegrate3Sound;//with inhuman scream disintLength = 2000; makeNotSolid = qtrue; break; /* case PW_SHOCKED:// arc welder disintEffect = EF_DISINT_1;//ef_ disintSound1 = NULL;//with scream disintSound2 = NULL;//no scream disintSound3 = NULL;//with inhuman scream disintLength = 4000; break; */ default: return; break; } if ( cent->gent->owner ) { cent->gent->owner->fx_time = cg.time; if ( cent->gent->owner->client ) { if ( disintSound1 && disintSound2 ) {//play an extra sound /* if ( cent->gent->owner->client->playerTeam == TEAM_STARFLEET || cent->gent->owner->client->playerTeam == TEAM_SCAVENGERS || cent->gent->owner->client->playerTeam == TEAM_MALON || cent->gent->owner->client->playerTeam == TEAM_IMPERIAL || cent->gent->owner->client->playerTeam == TEAM_HIROGEN || cent->gent->owner->client->playerTeam == TEAM_DISGUISE || cent->gent->owner->client->playerTeam == TEAM_KLINGON ) */ // listed all the non-humanoids, because there's a lot more humanoids class_t npc_class = cent->gent->owner->client->NPC_class; if( npc_class != CLASS_ATST && npc_class != CLASS_GONK && npc_class != CLASS_INTERROGATOR && npc_class != CLASS_MARK1 && npc_class != CLASS_MARK2 && npc_class != CLASS_MOUSE && npc_class != CLASS_PROBE && npc_class != CLASS_PROTOCOL && npc_class != CLASS_R2D2 && npc_class != CLASS_R5D2 && npc_class != CLASS_SEEKER && npc_class != CLASS_SENTRY) {//Only the humanoids scream cgi_S_StartSound ( NULL, cent->gent->owner->s.number, CHAN_VOICE, disintSound1 ); } // no more forge or 8472 // else if ( cent->gent->owner->client->playerTeam == TEAM_FORGE || // cent->gent->owner->client->playerTeam == TEAM_8472 ) // { // cgi_S_StartSound ( NULL, cent->gent->s.number, CHAN_VOICE, disintSound3 ); // } else { cgi_S_StartSound ( NULL, cent->gent->s.number, CHAN_AUTO, disintSound2 ); } } cent->gent->owner->s.powerups |= ( 1 << disintPW ); cent->gent->owner->client->ps.powerups[disintPW] = cg.time + disintLength; // Things that are being disintegrated should probably not be solid... if ( makeNotSolid && cent->gent->owner->client->playerTeam != TEAM_NEUTRAL ) { cent->gent->contents = CONTENTS_NONE; } } else { cent->gent->owner->s.eFlags = disintEffect;//FIXME: |= ? cent->gent->owner->delay = cg.time + disintLength; } } } break; // This does not necessarily have to be from a grenade... case EV_GRENADE_BOUNCE: DEBUGNAME("EV_GRENADE_BOUNCE"); CG_BounceEffect( cent, es->weapon, position, cent->gent->pos1 ); break; // // missile impacts // case EV_MISSILE_STICK: DEBUGNAME("EV_MISSILE_STICK"); CG_MissileStick( cent, es->weapon, position ); break; case EV_MISSILE_HIT: DEBUGNAME("EV_MISSILE_HIT"); CG_MissileHitPlayer( cent, es->weapon, position, cent->gent->pos1, cent->gent->alt_fire ); break; case EV_MISSILE_MISS: DEBUGNAME("EV_MISSILE_MISS"); CG_MissileHitWall( cent, es->weapon, position, cent->gent->pos1, cent->gent->alt_fire ); break; case EV_BMODEL_SOUND: DEBUGNAME("EV_BMODEL_SOUND"); cgi_S_StartSound( NULL, es->number, CHAN_AUTO, es->eventParm ); break; case EV_GENERAL_SOUND: DEBUGNAME("EV_GENERAL_SOUND"); if ( cgs.sound_precache[ es->eventParm ] ) { cgi_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.sound_precache[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); CG_TryPlayCustomSound(NULL, es->number, CHAN_AUTO, s, CS_BASIC ); } break; case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes DEBUGNAME("EV_GLOBAL_SOUND"); if ( cgs.sound_precache[ es->eventParm ] ) { cgi_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.sound_precache[ es->eventParm ] ); } else { s = CG_ConfigString( CS_SOUNDS + es->eventParm ); CG_TryPlayCustomSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, s, CS_BASIC ); } break; case EV_DRUGGED: DEBUGNAME("EV_DRUGGED"); if ( cent->gent && cent->gent->owner && cent->gent->owner->s.number == 0 ) { // Only allow setting up the wonky vision on the player..do it for 10 seconds...must be synchronized with calcs done in cg_view. Just search for cg.wonkyTime to find 'em. cg.wonkyTime = cg.time + 10000; } break; case EV_PAIN: { char *snd; const int health = es->eventParm; if ( cent->gent && cent->gent->NPC && (cent->gent->NPC->aiFlags & NPCAI_DIE_ON_IMPACT) ) { return; } //FIXME: don't do this if we're falling to our deaths... DEBUGNAME("EV_PAIN"); // don't do more than two pain sounds a second if ( cg.time - cent->pe.painTime < 500 ) { return; } if ( health < 25 ) { snd = "*pain100.wav"; } else if ( health < 50 ) { snd = "*pain75.wav"; } else if ( health < 75 ) { snd = "*pain50.wav"; } else { snd = "*pain25.wav"; } CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, snd, CS_BASIC ); // save pain time for programitic twitch animation cent->pe.painTime = cg.time; cent->pe.painDirection ^= 1; } break; case EV_DEATH1: case EV_DEATH2: case EV_DEATH3: DEBUGNAME("EV_DEATHx"); /* if ( cent->gent && cent->gent->NPC && (cent->gent->NPC->aiFlags & NPCAI_DIE_ON_IMPACT) ) { return; } */ CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*death%i.wav", event - EV_DEATH1 + 1), CS_BASIC ); break; // Called by the FxRunner entity...usually for Environmental FX Events case EV_PLAY_EFFECT: DEBUGNAME("EV_PLAY_EFFECT"); s = CG_ConfigString( CS_EFFECTS + es->eventParm ); // Ghoul2 Insert Start if (es->boltInfo != 0) { theFxScheduler.PlayEffect( s, cent->lerpOrigin, axis, es->boltInfo, -1 ); } else { VectorCopy( cent->gent->pos3, axis[0] ); VectorCopy( cent->gent->pos4, axis[1] ); CrossProduct( axis[0], axis[1], axis[2] ); // the entNum the effect may be attached to if ( es->otherEntityNum ) { theFxScheduler.PlayEffect( s, cent->lerpOrigin, axis, -1, es->otherEntityNum ); } else { theFxScheduler.PlayEffect( s, cent->lerpOrigin, axis, -1, -1 ); } } // Ghoul2 Insert End break; // play an effect bolted onto a muzzle case EV_PLAY_MUZZLE_EFFECT: DEBUGNAME("EV_PLAY_MUZZLE_EFFECT"); s = CG_ConfigString( CS_EFFECTS + es->eventParm ); theFxScheduler.PlayEffect( s, es->otherEntityNum ); break; case EV_TARGET_BEAM_DRAW: DEBUGNAME("EV_TARGET_BEAM_DRAW"); if ( cent->gent ) { s = CG_ConfigString( CS_EFFECTS + es->eventParm ); if ( s && s[0] ) { if ( cent->gent->delay ) { s2 = CG_ConfigString( CS_EFFECTS + cent->gent->delay ); } else { s2 = NULL; } CG_DrawTargetBeam( cent->lerpOrigin, cent->gent->s.origin2, cent->gent->pos1, s, s2 ); } /* else { int gack = 0; // this is bad if it get's here } */ } break; case EV_ANGER1: //Say when acquire an enemy when didn't have one before case EV_ANGER2: case EV_ANGER3: DEBUGNAME("EV_ANGERx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*anger%i.wav", event - EV_ANGER1 + 1), CS_COMBAT ); break; case EV_VICTORY1: //Say when killed an enemy case EV_VICTORY2: case EV_VICTORY3: DEBUGNAME("EV_VICTORYx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*victory%i.wav", event - EV_VICTORY1 + 1), CS_COMBAT ); break; case EV_CONFUSE1: //Say when confused case EV_CONFUSE2: case EV_CONFUSE3: DEBUGNAME("EV_CONFUSEDx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*confuse%i.wav", event - EV_CONFUSE1 + 1), CS_COMBAT ); break; case EV_PUSHED1: //Say when pushed case EV_PUSHED2: case EV_PUSHED3: DEBUGNAME("EV_PUSHEDx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*pushed%i.wav", event - EV_PUSHED1 + 1), CS_COMBAT ); break; case EV_CHOKE1: //Say when choking case EV_CHOKE2: case EV_CHOKE3: DEBUGNAME("EV_CHOKEx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*choke%i.wav", event - EV_CHOKE1 + 1), CS_COMBAT ); break; case EV_FFWARN: //Warn ally to stop shooting you DEBUGNAME("EV_FFWARN"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*ffwarn.wav", CS_COMBAT ); break; case EV_FFTURN: //Turn on ally after being shot by them DEBUGNAME("EV_FFTURN"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*ffturn.wav", CS_COMBAT ); break; //extra sounds for ST case EV_CHASE1: case EV_CHASE2: case EV_CHASE3: DEBUGNAME("EV_CHASEx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*chase%i.wav", event - EV_CHASE1 + 1), CS_EXTRA ); break; case EV_COVER1: case EV_COVER2: case EV_COVER3: case EV_COVER4: case EV_COVER5: DEBUGNAME("EV_COVERx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*cover%i.wav", event - EV_COVER1 + 1), CS_EXTRA ); break; case EV_DETECTED1: case EV_DETECTED2: case EV_DETECTED3: case EV_DETECTED4: case EV_DETECTED5: DEBUGNAME("EV_DETECTEDx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*detected%i.wav", event - EV_DETECTED1 + 1), CS_EXTRA ); break; case EV_GIVEUP1: case EV_GIVEUP2: case EV_GIVEUP3: case EV_GIVEUP4: DEBUGNAME("EV_GIVEUPx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*giveup%i.wav", event - EV_GIVEUP1 + 1), CS_EXTRA ); break; case EV_LOOK1: case EV_LOOK2: DEBUGNAME("EV_LOOKx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*look%i.wav", event - EV_LOOK1 + 1), CS_EXTRA ); break; case EV_LOST1: DEBUGNAME("EV_LOST1"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*lost1.wav", CS_EXTRA ); break; case EV_OUTFLANK1: case EV_OUTFLANK2: DEBUGNAME("EV_OUTFLANKx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*outflank%i.wav", event - EV_OUTFLANK1 + 1), CS_EXTRA ); break; case EV_ESCAPING1: case EV_ESCAPING2: case EV_ESCAPING3: DEBUGNAME("EV_ESCAPINGx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*escaping%i.wav", event - EV_ESCAPING1 + 1), CS_EXTRA ); break; case EV_SIGHT1: case EV_SIGHT2: case EV_SIGHT3: DEBUGNAME("EV_SIGHTx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*sight%i.wav", event - EV_SIGHT1 + 1), CS_EXTRA ); break; case EV_SOUND1: case EV_SOUND2: case EV_SOUND3: DEBUGNAME("EV_SOUNDx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*sound%i.wav", event - EV_SOUND1 + 1), CS_EXTRA ); break; case EV_SUSPICIOUS1: case EV_SUSPICIOUS2: case EV_SUSPICIOUS3: case EV_SUSPICIOUS4: case EV_SUSPICIOUS5: DEBUGNAME("EV_SUSPICIOUSx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*suspicious%i.wav", event - EV_SUSPICIOUS1 + 1), CS_EXTRA ); break; //extra sounds for Jedi case EV_COMBAT1: case EV_COMBAT2: case EV_COMBAT3: DEBUGNAME("EV_COMBATx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*combat%i.wav", event - EV_COMBAT1 + 1), CS_JEDI ); break; case EV_JDETECTED1: case EV_JDETECTED2: case EV_JDETECTED3: DEBUGNAME("EV_JDETECTEDx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*jdetected%i.wav", event - EV_JDETECTED1 + 1), CS_JEDI ); break; case EV_TAUNT1: case EV_TAUNT2: case EV_TAUNT3: DEBUGNAME("EV_TAUNTx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*taunt%i.wav", event - EV_TAUNT1 + 1), CS_JEDI ); break; case EV_JCHASE1: case EV_JCHASE2: case EV_JCHASE3: DEBUGNAME("EV_JCHASEx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*jchase%i.wav", event - EV_JCHASE1 + 1), CS_JEDI ); break; case EV_JLOST1: case EV_JLOST2: case EV_JLOST3: DEBUGNAME("EV_JLOSTx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*jlost%i.wav", event - EV_JLOST1 + 1), CS_JEDI ); break; case EV_DEFLECT1: case EV_DEFLECT2: case EV_DEFLECT3: DEBUGNAME("EV_DEFLECTx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*deflect%i.wav", event - EV_DEFLECT1 + 1), CS_JEDI ); break; case EV_GLOAT1: case EV_GLOAT2: case EV_GLOAT3: DEBUGNAME("EV_GLOATx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*gloat%i.wav", event - EV_GLOAT1 + 1), CS_JEDI ); break; case EV_PUSHFAIL: DEBUGNAME("EV_PUSHFAIL"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*pushfail.wav", CS_JEDI ); break; case EV_USE_FORCE: DEBUGNAME("EV_USE_FORCEITEM"); CG_UseForce( cent ); break; case EV_USE_ITEM: DEBUGNAME("EV_USE_ITEM"); CG_UseItem( cent ); break; case EV_USE_INV_BINOCULARS: DEBUGNAME("EV_USE_INV_BINOCULARS"); UseItem(INV_ELECTROBINOCULARS ); break; case EV_USE_INV_BACTA: DEBUGNAME("EV_USE_INV_BACTA"); UseItem(INV_BACTA_CANISTER ); break; case EV_USE_INV_SEEKER: DEBUGNAME("EV_USE_INV_SEEKER"); UseItem(INV_SEEKER ); break; case EV_USE_INV_LIGHTAMP_GOGGLES: DEBUGNAME("EV_USE_INV_LIGHTAMP_GOGGLES"); UseItem(INV_LIGHTAMP_GOGGLES ); break; case EV_USE_INV_SENTRY: DEBUGNAME("EV_USE_INV_SENTRY"); UseItem(INV_SENTRY ); break; case EV_DEBUG_LINE: DEBUGNAME("EV_DEBUG_LINE"); CG_TestLine(position, es->origin2, es->time, (unsigned int)(es->time2), es->weapon); break; default: DEBUGNAME("UNKNOWN"); CG_Error( "Unknown event: %i", event ); break; } }
void CG_LoadLocations(void) { fileHandle_t f; // handle of file on disk int fLen = trap_FS_FOpenFile(va("maps/%s_loc_override.dat", cgs.rawmapname), &f, FS_READ); // length of the file char fBuffer[MAX_BUFFER]; // buffer to read the file into char message[128] = "\0"; // location description char temp[128] = "\0"; // temporary buffer int x = 0; // x-coord of the location int y = 0; // y-coord of the location int z = 0; // z-coord of the location int p = 0; // current location in the file buffer int t = 0; // current location in the temp buffer if (fLen < 0) { // open the location .dat file that matches the map's name fLen = trap_FS_FOpenFile(va("maps/%s_loc.dat", cgs.rawmapname), &f, FS_READ); if (fLen < 0) { CG_Printf("^dLoadLocations: ^3Warning: ^9No location data found for map ^2%s^9.\n", cgs.rawmapname); return; } } if (fLen > MAX_BUFFER) { trap_FS_FCloseFile(f); CG_Error("Location file is too big, make it smaller (max = %i bytes)\n", MAX_BUFFER); } trap_FS_Read(&fBuffer, fLen, f); // read the file into the buffer fBuffer[fLen] = '\0'; // make sure it's null-terminated trap_FS_FCloseFile(f); // close the file, we're done with it CG_Printf("^dLoadLocations: ^9location data for map ^2%s ^9loaded\n", cgs.rawmapname); // start parsing! while (p < fLen) { // check for the beginning of a comment if (fBuffer[p++] == '/') { //check for single line comment if (fBuffer[p] == '/') { while (p < fLen && (fBuffer[p] != '\n' && fBuffer[p] != '\r')) { p++; } } // check for multiline comment else if (fBuffer[p] == '*') { while (p < fLen && (fBuffer[p] != '*' && fBuffer[p + 1] != '/')) { p++; } } } // parse the next line while (p < fLen && (fBuffer[p] != '\n' || fBuffer[p] != '\r')) { // grab the x-coord while (p < fLen && fBuffer[p] != ' ') { temp[t++] = fBuffer[p++]; } temp[t] = '\0'; x = atoi(temp); t = 0; memset(&temp, 0, sizeof(temp)); if (p > fLen) { break; } p++; // grab the y-coord while (p < fLen && fBuffer[p] != ' ') { temp[t++] = fBuffer[p++]; } temp[t] = '\0'; y = atoi(temp); t = 0; memset(&temp, 0, sizeof(temp)); if (p > fLen) { break; } p++; // grab the z-coord while (p < fLen && fBuffer[p] != ' ') { temp[t++] = fBuffer[p++]; } temp[t] = '\0'; z = atoi(temp); t = 0; memset(&temp, 0, sizeof(temp)); if (p > fLen) { break; } p++; // grab the description while (p < fLen && fBuffer[p] != '\n' && fBuffer[p] != '\r') { // ignore quotation marks if (fBuffer[p] != '\"') { temp[t++] = fBuffer[p++]; } else { p++; } } temp[t] = '\0'; t = 0; // if @, then keep the previous location name, otherwise, update message if (Q_stricmp(temp, "@")) { strcpy(message, temp); } if (p > fLen) { break; } if ((x != 0 || y != 0 || z != 0) && strlen(message) > 0) { location_t *loc = &cgs.location[cgs.numLocations]; loc->index = cgs.numLocations; strcpy(loc->message, message); loc->origin[0] = x; loc->origin[1] = y; loc->origin[2] = z; cgs.numLocations++; if (cgs.numLocations == MAX_C_LOCATIONS) { CG_Printf("^9Too many locations specifed.\n"); break; } } } } // ok we are succesfull CG_Printf("^2%i ^9locations loaded.\n", cgs.numLocations); cgs.locationsLoaded = qtrue; }
void CG_TestModelNextFrame_f(void) { cg.testModelEntity.frame++; CG_Printf("frame %i\n", cg.testModelEntity.frame); }
/* ============= CG_Obituary ============= */ static void CG_Obituary( entityState_t *ent ) { int mod; int target, attacker; char *message; char *message2; const char *targetInfo; const char *attackerInfo; char targetName[32]; char attackerName[32]; gender_t gender; clientInfo_t *ci; target = ent->otherEntityNum; attacker = ent->otherEntityNum2; mod = ent->eventParm; if ( target < 0 || target >= MAX_CLIENTS ) { CG_Error( "CG_Obituary: target out of range" ); } ci = &cgs.clientinfo[target]; if ( attacker < 0 || attacker >= MAX_CLIENTS ) { attacker = ENTITYNUM_WORLD; attackerInfo = NULL; } else { attackerInfo = CG_ConfigString( CS_PLAYERS + attacker ); } targetInfo = CG_ConfigString( CS_PLAYERS + target ); if ( !targetInfo ) { return; } Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2); strcat( targetName, S_COLOR_WHITE ); message2 = ""; // check for single client messages switch( mod ) { case MOD_SUICIDE: message = "suicides"; break; case MOD_FALLING: message = "cratered"; break; case MOD_CRUSH: message = "was squished"; break; case MOD_WATER: message = "sank like a rock"; break; case MOD_SLIME: message = "melted"; break; case MOD_LAVA: message = "does a back flip into the lava"; break; case MOD_TARGET_LASER: message = "saw the light"; break; case MOD_TRIGGER_HURT: message = "was in the wrong place"; break; default: message = NULL; break; } if (attacker == target) { gender = ci->gender; switch (mod) { #ifdef MISSIONPACK case MOD_KAMIKAZE: message = "goes out with a bang"; break; #endif case MOD_GRENADE_SPLASH: if ( gender == GENDER_FEMALE ) message = "tripped on her own grenade"; else if ( gender == GENDER_NEUTER ) message = "tripped on its own grenade"; else message = "tripped on his own grenade"; break; case MOD_ROCKET_SPLASH: if ( gender == GENDER_FEMALE ) message = "blew herself up"; else if ( gender == GENDER_NEUTER ) message = "blew itself up"; else message = "blew himself up"; break; case MOD_PLASMA_SPLASH: if ( gender == GENDER_FEMALE ) message = "melted herself"; else if ( gender == GENDER_NEUTER ) message = "melted itself"; else message = "melted himself"; break; case MOD_BFG_SPLASH: message = "should have used a smaller gun"; break; #ifdef MISSIONPACK case MOD_PROXIMITY_MINE: if( gender == GENDER_FEMALE ) { message = "found her prox mine"; } else if ( gender == GENDER_NEUTER ) { message = "found its prox mine"; } else { message = "found his prox mine"; } break; #endif default: if ( gender == GENDER_FEMALE ) message = "killed herself"; else if ( gender == GENDER_NEUTER ) message = "killed itself"; else message = "killed himself"; break; } } if (message) { CG_Printf( "%s %s.\n", targetName, message); return; } // check for kill messages from the current clientNum if ( attacker == cg.snap->ps.clientNum ) { char *s; if ( cgs.gametype < GT_TEAM ) { s = va("You fragged %s\n%s place with %i", targetName, CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), cg.snap->ps.persistant[PERS_SCORE] ); } else { s = va("You fragged %s", targetName ); } #ifdef MISSIONPACK if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) { CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); } #else CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); #endif // print the text message as well } // check for double client messages if ( !attackerInfo ) { attacker = ENTITYNUM_WORLD; strcpy( attackerName, "noname" ); } else { Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2); strcat( attackerName, S_COLOR_WHITE ); // check for kill messages about the current clientNum if ( target == cg.snap->ps.clientNum ) { Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) ); } } if ( attacker != ENTITYNUM_WORLD ) { switch (mod) { case MOD_GRAPPLE: message = "was caught by"; break; case MOD_GAUNTLET: message = "was pummeled by"; break; case MOD_MACHINEGUN: message = "was machinegunned by"; break; case MOD_SHOTGUN: message = "was gunned down by"; break; case MOD_GRENADE: message = "ate"; message2 = "'s grenade"; break; case MOD_GRENADE_SPLASH: message = "was shredded by"; message2 = "'s shrapnel"; break; case MOD_ROCKET: message = "ate"; message2 = "'s rocket"; break; case MOD_ROCKET_SPLASH: message = "almost dodged"; message2 = "'s rocket"; break; case MOD_PLASMA: message = "was melted by"; message2 = "'s plasmagun"; break; case MOD_PLASMA_SPLASH: message = "was melted by"; message2 = "'s plasmagun"; break; case MOD_RAILGUN: message = "was railed by"; break; case MOD_LIGHTNING: message = "was electrocuted by"; break; case MOD_BFG: case MOD_BFG_SPLASH: message = "was blasted by"; message2 = "'s BFG"; break; #ifdef MISSIONPACK case MOD_NAIL: message = "was nailed by"; break; case MOD_CHAINGUN: message = "got lead poisoning from"; message2 = "'s Chaingun"; break; case MOD_PROXIMITY_MINE: message = "was too close to"; message2 = "'s Prox Mine"; break; case MOD_KAMIKAZE: message = "falls to"; message2 = "'s Kamikaze blast"; break; case MOD_JUICED: message = "was juiced by"; break; #endif case MOD_TELEFRAG: message = "tried to invade"; message2 = "'s personal space"; break; default: message = "was killed by"; break; } if (message) { CG_Printf( "%s %s %s%s\n", targetName, message, attackerName, message2); return; } } // we don't know what it was CG_Printf( "%s died.\n", targetName ); }
void CG_TestModelNextSkin_f(void) { cg.testModelEntity.skinNum++; CG_Printf("skin %i\n", cg.testModelEntity.skinNum); }
/* ====================== CG_ParseBuildableAnimationFile Read a configuration file containing animation counts and rates models/buildables/hivemind/animation.cfg, etc ====================== */ static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_t buildable ) { char *text_p; int len; int i; char *token; float fps; char text[ 20000 ]; fileHandle_t f; animation_t *animations; animations = cg_buildables[ buildable ].animations; // load the file len = trap_FS_FOpenFile( filename, &f, FS_READ ); if( len < 0 ) return qfalse; if( len == 0 || len >= sizeof( text ) - 1 ) { trap_FS_FCloseFile( f ); CG_Printf( "File %s is %s\n", filename, len == 0 ? "empty" : "too long" ); return qfalse; } trap_FS_Read( text, len, f ); text[ len ] = 0; trap_FS_FCloseFile( f ); // parse the text text_p = text; // read information for each frame for( i = BANIM_NONE + 1; i < MAX_BUILDABLE_ANIMATIONS; i++ ) { token = COM_Parse( &text_p ); if( !*token ) break; animations[ i ].firstFrame = atoi( token ); token = COM_Parse( &text_p ); if( !*token ) break; animations[ i ].numFrames = atoi( token ); animations[ i ].reversed = qfalse; animations[ i ].flipflop = qfalse; // if numFrames is negative the animation is reversed if( animations[ i ].numFrames < 0 ) { animations[ i ].numFrames = -animations[ i ].numFrames; animations[ i ].reversed = qtrue; } token = COM_Parse( &text_p ); if ( !*token ) break; animations[i].loopFrames = atoi( token ); token = COM_Parse( &text_p ); if( !*token ) break; fps = atof( token ); if( fps == 0 ) fps = 1; animations[ i ].frameLerp = 1000 / fps; animations[ i ].initialLerp = 1000 / fps; } if( i != MAX_BUILDABLE_ANIMATIONS ) { CG_Printf( "Error parsing animation file: %s\n", filename ); return qfalse; } return qtrue; }
/** Generates and draws a game scene and status information at the given time. */ void CG_DrawActiveFrame(int serverTime, stereoFrame_t stereoView, qboolean demoPlayback) { int inwater; cg.totalTime = serverTime; // TODO predict pause end and pauseTime which is useful for high ping players if (cgs.pauseStart) { cg.time = cgs.pauseStart; } else { // cg.time needs to be the same as level.time, otherwise // animations and missiles will skip cg.time = cg.totalTime - cgs.pauseTime; } cg.demoPlayback = demoPlayback; // get the rendering configuration from the client system trap_GetGlconfig(&cgs.glconfig); cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if (cg.showInfoScreen) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if (!cg.snap || (cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE)) { CG_DrawInformation(); return; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue(cg.weaponSelect, cg.zoomSensitivity); // this counter will be bumped for every valid scene we generate cg.clientFrame++; // update cg.predictedPlayerState CG_PredictPlayerState(); // decide on third person view cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); // build cg.refdef inwater = CG_CalcViewValues(); // first person blend blobs, done after AnglesToAxis if (!cg.renderingThirdPerson) { CG_DamageBlendBlob(); } // build the render lists if (!cg.hyperspace) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddParticles(); CG_AddLocalEntities(); CG_AddSpawnpoints(); } CG_AddViewWeapon(&cg.predictedPlayerState); // add buffered sounds CG_PlayBufferedSounds(); // finish up the rest of the refdef if (cg.testModelEntity.hModel) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy(cg.refdef.areamask, cg.snap->areamask, sizeof(cg.refdef.areamask)); CG_CountdownSounds(); CG_PopReward(); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // update audio positions trap_S_Respatialize(cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater); // make sure the lagometerSample and frame timing isn't done twice when in stereo if (stereoView != STEREO_RIGHT) { cg.frametime = cg.time - cg.oldTime; if (cg.frametime < 0) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive(stereoView); if (cg_stats.integer) { CG_Printf("cg.clientFrame:%i\n", cg.clientFrame); } }
void CG_LoadHolsterData (clientInfo_t *ci) {//adjusts the manual holster positional data based on the holster.cfg file associated with the model or simply //use the default values int i; fileHandle_t f; int fLen = 0; char fileBuffer[MAX_HOLSTER_INFO_SIZE]; char holsterTypeValue[MAX_QPATH]; char holsterTypeGroup[MAX_HOLSTER_INFO_SIZE]; char *s; vec3_t vectorData; InitHolsterData(ci); if ( !ci->skinName || !Q_stricmp( "default", ci->skinName ) ) {//try default holster.cfg first fLen = trap_FS_FOpenFile(va("models/players/%s/holster.cfg", ci->modelName), &f, FS_READ); if( !f ) {//no file, use kyle's then. fLen = trap_FS_FOpenFile("models/players/kyle/holster.cfg", &f, FS_READ); } } else {//use the holster.cfg associated with this skin fLen = trap_FS_FOpenFile(va("models/players/%s/holster_%s.cfg", ci->modelName, ci->skinName), &f, FS_READ); if ( !f ) {//fall back to default holster.cfg fLen = trap_FS_FOpenFile(va("models/players/%s/holster.cfg", ci->modelName), &f, FS_READ); } if( !f ) {//still no dice, use kyle's then. fLen = trap_FS_FOpenFile("models/players/kyle/holster.cfg", &f, FS_READ); } } if ( !f || !fLen ) {//couldn't open file or it was empty, just use the defaults return; } if( fLen >= MAX_HOLSTER_INFO_SIZE ) { CG_Printf("Error: holster.cfg for %s is over the holster.cfg filesize limit.\n", ci->modelName); trap_FS_FCloseFile( f ); return; } trap_FS_Read(fileBuffer, fLen, f); trap_FS_FCloseFile( f ); s = fileBuffer; //parse file while( (s = BG_GetNextValueGroup(s, holsterTypeGroup)) != NULL ) { if( !BG_SiegeGetPairedValue(holsterTypeGroup, "holsterType", holsterTypeValue) ) {//couldn't find holster type in group CG_Printf("Error: The holster.cfg for %s appears to be missing a holsterType in one of its define groups.\n", ci->modelName); continue; } i = GetIDForString(holsterTypeTable, holsterTypeValue); if( i == -1 ) {//bad holster type CG_Printf("Error: The holster.cfg for %s has a bad holsterType in one of the define groups.\n", ci->modelName); continue; } if( BG_SiegeGetPairedValue(holsterTypeGroup, "boneIndex", holsterTypeValue) ) {//have bone index data for this holster type, use it if(!Q_stricmp(holsterTypeValue, "disabled") ) {//disable the rendering of this holster type on this model ci->holsterData[i].boneIndex = HOLSTER_NONE; } else { ci->holsterData[i].boneIndex = GetIDForString(holsterBoneTable, holsterTypeValue); } } if( BG_SiegeGetPairedValue(holsterTypeGroup, "posOffset", holsterTypeValue) ) {//parsing positional offset data sscanf (holsterTypeValue, "%f, %f, %f", &vectorData[0], &vectorData[1], &vectorData[2]); VectorCopy(vectorData, ci->holsterData[i].posOffset); //&ci->holsterData[i].posOffset[0], &ci->holsterData[i].posOffset[1], //&ci->holsterData[i].posOffset[2]); } if( BG_SiegeGetPairedValue(holsterTypeGroup, "angOffset", holsterTypeValue) ) {//parsing angular offset sscanf (holsterTypeValue, "%f, %f, %f", &vectorData[0], &vectorData[1], &vectorData[2]); VectorCopy(vectorData, ci->holsterData[i].angOffset); } } #ifdef _DEBUG CG_Printf("Holstered Weapon Data Loaded for %s.\n", ci->modelName); #endif }
void JKG_DrawWeaponHolsters( centity_t *cent, refEntity_t legs, float shadowPlane ) { if (cent->currentState.weapon > 0 // UQ1: Issues with weapon 0??? && !(cent->currentState.number == cg.predictedPlayerState.clientNum && !cg.renderingThirdPerson) && cent->currentState.number == cg.clientNum // UQ1: Enemy ones??? Best data transfer method??? && (cent && cent->ghoul2 && cent->currentState.eType != ET_NPC)) { int HOLSTER_POINT = 0; int NUM_HOLSTERS = 5; // UQ1: Extra 2 look stupid... int i = 0; cgItemData_t *LIGHT_ITEMS_LIST[5]; cgItemData_t *HEAVY_ITEMS_LIST[5]; int NUM_LIGHT_ITEMS = 0; int NUM_HEAVY_ITEMS = 0; #ifdef _DEBUG //CG_Printf("Adding holster items...\n"); #endif //_DEBUG for (i = 0; i < 3; i++) LIGHT_ITEMS_LIST[i] = NULL; for (i = 0; i < 2; i++) HEAVY_ITEMS_LIST[i] = NULL; // Create Light Items List... for (i = 0; i < MAX_ACI_SLOTS; i++) { unsigned int weap, var; // FIXME: How to get enemy player ACI list???? // Events? Even the data for just 4 holsters would be crazy... if (cg.playerACI[i] < 0) continue; if (cg.playerInventory[cg.playerACI[i]].id->weapon == cg.predictedPlayerState.weapon) continue; if (cg.playerInventory[cg.playerACI[i]].equipped) continue; if (!cg.playerInventory[cg.playerACI[i]].id) continue; weap = cg.playerInventory[cg.playerACI[i]].id->weapon; var = cg.playerInventory[cg.playerACI[i]].id->variation; // How did this get through equipped above??? if (weap == cent->currentState.weapon) continue; // Quick and dirty choice of where to put guns based on weight... if (cg.playerInventory[cg.playerACI[i]].id->weight > 1) continue; // Too heavy for waist... // FIXME: Sort by new WEAPON_TYPE value... LIGHT_ITEMS_LIST[NUM_LIGHT_ITEMS] = cg.playerInventory[cg.playerACI[i]].id; NUM_LIGHT_ITEMS++; if (NUM_LIGHT_ITEMS >= 3) break; // Full... } // Create Heavy Items List... for (i = 0; i < MAX_ACI_SLOTS; i++) { unsigned int weap, var; // FIXME: How to get enemy player ACI list???? // Events? Even the data for just 4 holsters would be crazy... if (cg.playerACI[i] < 0) continue; if (cg.playerInventory[cg.playerACI[i]].equipped) continue; if (!cg.playerInventory[cg.playerACI[i]].id) continue; weap = cg.playerInventory[cg.playerACI[i]].id->weapon; var = cg.playerInventory[cg.playerACI[i]].id->variation; // How did this get through equipped above??? if (weap == cent->currentState.weapon) continue; // Quick and dirty choice of where to put guns based on weight... if (cg.playerInventory[cg.playerACI[i]].id->weight <= 1) continue; // Too light for back... // FIXME: Sort by new WEAPON_TYPE value... HEAVY_ITEMS_LIST[NUM_HEAVY_ITEMS] = cg.playerInventory[cg.playerACI[i]].id; NUM_HEAVY_ITEMS++; if (NUM_HEAVY_ITEMS >= 2) break; // Full... } for(HOLSTER_POINT = 0; HOLSTER_POINT < NUM_HOLSTERS; HOLSTER_POINT++) { void *weaponGhoul2 = NULL; refEntity_t holsterRefEnt; int WEAPON_NUM = 0; weaponInfo_t *weapon = NULL; if (HOLSTER_POINT == 0 && NUM_LIGHT_ITEMS < 1) continue; // No more light items to draw... if (HOLSTER_POINT == 1 && NUM_LIGHT_ITEMS < 2) continue; // No more light items to draw... //if (HOLSTER_POINT == 2 && NUM_LIGHT_ITEMS < 3) continue; // No more light items to draw... if (HOLSTER_POINT == 2) continue; // Disabled... if (HOLSTER_POINT == 3 && NUM_HEAVY_ITEMS < 1) continue; // No more heavy items to draw... if (HOLSTER_POINT == 4 && NUM_HEAVY_ITEMS < 2) continue; // No more heavy items to draw... if (HOLSTER_POINT < 3) { if (LIGHT_ITEMS_LIST[HOLSTER_POINT]) { // Light Items (waist)... WEAPON_NUM = LIGHT_ITEMS_LIST[HOLSTER_POINT]->weapon; if (WEAPON_NUM <= 0) continue; weapon = CG_WeaponInfo (WEAPON_NUM, LIGHT_ITEMS_LIST[HOLSTER_POINT]->variation); } else { continue; } } else { if (HEAVY_ITEMS_LIST[HOLSTER_POINT-3]) { // Heavy Items (back)... WEAPON_NUM = HEAVY_ITEMS_LIST[HOLSTER_POINT-3]->weapon; if (WEAPON_NUM <= 0) continue; weapon = CG_WeaponInfo (WEAPON_NUM, HEAVY_ITEMS_LIST[HOLSTER_POINT-3]->variation); } else { continue; } } if (!weapon) continue; memset( &holsterRefEnt, 0, sizeof( holsterRefEnt ) ); weaponGhoul2 = weapon->g2WorldModel; if (trap_G2_HaveWeGhoul2Models(weaponGhoul2)) { char bone_name[MAX_QPATH]; vec3_t holsterAngles, end, fwd, rt, originalOrigin; // UQ1: Which bone are we using? if (HOLSTER_POINT == 0) Q_strncpyz( bone_name , "pelvis", sizeof( bone_name ) ); if (HOLSTER_POINT == 1) Q_strncpyz( bone_name , "pelvis", sizeof( bone_name ) ); if (HOLSTER_POINT == 2) Q_strncpyz( bone_name , "thoracic", sizeof( bone_name ) ); if (HOLSTER_POINT == 3) Q_strncpyz( bone_name , "thoracic", sizeof( bone_name ) ); if (HOLSTER_POINT == 4) Q_strncpyz( bone_name , "thoracic", sizeof( bone_name ) ); //if (HOLSTER_POINT == 4) Q_strncpyz( bone_name , "ltibia", sizeof( bone_name ) ); // UQ1: These look really dumb.... //if (HOLSTER_POINT == 5) Q_strncpyz( bone_name , "rtibia", sizeof( bone_name ) ); // UQ1: These look really dumb.... // UQ1: Set exact org/angles for this bone... if (!CG_SnapRefEntToBone(cent, &holsterRefEnt, bone_name)) { #ifdef _DEBUG CG_Printf("Holster point %i NOT drawn (snap to bone issue)...\n", HOLSTER_POINT); assert(0); #endif // continue; } VectorCopy( legs.modelScale, holsterRefEnt.modelScale); holsterRefEnt.radius = legs.radius; VectorCopy(holsterRefEnt.origin, originalOrigin); VectorCopy(cent->lerpAngles, holsterAngles); holsterAngles[PITCH] = 0; holsterAngles[ROLL] = 0; AngleVectors( holsterAngles, fwd, rt, NULL ); // UQ1: Now modify the org/angles... switch (HOLSTER_POINT) { case 0: // "pelvis" left VectorMA( originalOrigin, -2, fwd, end ); VectorMA( end, -6, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 8; // because the bones suck for placement... //AxisToAngles(holsterRefEnt.axis, holsterAngles); holsterAngles[PITCH] += 90; //holsterAngles[YAW] -= 90; holsterAngles[ROLL] += 90; holsterAngles[PITCH] += 30; holsterAngles[YAW] -= 50; holsterAngles[ROLL] -= 50; break; case 1: // "pelvis" right VectorMA( originalOrigin, -2, fwd, end ); VectorMA( end, 6, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 8; // because the bones suck for placement... //AxisToAngles(holsterRefEnt.axis, holsterAngles); holsterAngles[PITCH] += 90; holsterAngles[YAW] += 180; holsterAngles[ROLL] += 90; holsterAngles[PITCH] -= 30; holsterAngles[YAW] += 50; holsterAngles[ROLL] += 50; break; case 2: // "thoracic" left - used for center pistol - where on the back is this meant to fit??? VectorMA( originalOrigin, -4, fwd, end ); VectorMA( end, -2, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 8; // because the bones suck for placement... //AxisToAngles(holsterRefEnt.axis, holsterAngles); holsterAngles[PITCH] += 90; //holsterAngles[YAW] -= 90; holsterAngles[ROLL] += 90; holsterAngles[PITCH] += 10;//d_poff.value; holsterAngles[YAW] += 0;//d_yoff.value; holsterAngles[ROLL] += 0;//d_roff.value; break; case 3: // "thoracic" left VectorMA( originalOrigin, -4, fwd, end ); VectorMA( end, -6, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 6; // because the bones suck for placement... //AxisToAngles(holsterRefEnt.axis, holsterAngles); holsterAngles[PITCH] += 90; //holsterAngles[YAW] -= 90; holsterAngles[ROLL] += 90; holsterAngles[PITCH] += 10 + 25; holsterAngles[YAW] += 50 + 15; holsterAngles[ROLL] += 50; break; case 4: // "thoracic" right VectorMA( originalOrigin, -4, fwd, end ); VectorMA( end, 6, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 6; // because the bones suck for placement... //AxisToAngles(holsterRefEnt.axis, holsterAngles); holsterAngles[PITCH] += 90; holsterAngles[YAW] += 180; holsterAngles[ROLL] += 90; holsterAngles[PITCH] -= 10 + 25; holsterAngles[YAW] -= 50 + 15; holsterAngles[ROLL] -= 50; break; /*case 5: // UQ1: These look really dumb.... // "ltibia" VectorMA( originalOrigin, -4, fwd, end ); VectorMA( end, -4, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 8; // because the bones suck for placement... holsterAngles[PITCH] += 90; //holsterAngles[YAW] -= 90; holsterAngles[ROLL] += 90; holsterAngles[PITCH] -= d_poff.value; holsterAngles[YAW] -= d_yoff.value; holsterAngles[ROLL] -= d_roff.value; break; case 6: // UQ1: These look really dumb.... // "rtibia" VectorMA( originalOrigin, -4, fwd, end ); VectorMA( end, 4, rt, end ); VectorCopy(end, holsterRefEnt.origin); holsterRefEnt.origin[2] += 8; // because the bones suck for placement... holsterAngles[PITCH] += 90; holsterAngles[YAW] += 180; holsterAngles[ROLL] += 90; holsterAngles[PITCH] += d_poff.value; holsterAngles[YAW] += d_yoff.value; holsterAngles[ROLL] += d_roff.value; break;*/ default: continue; // should never see this... break; } holsterRefEnt.reType = RT_MODEL; holsterRefEnt.hModel = 0; holsterRefEnt.ghoul2 = weaponGhoul2; AnglesToAxis(holsterAngles, holsterRefEnt.axis); holsterRefEnt.shadowPlane = shadowPlane; CG_AddWeaponWithPowerups( &holsterRefEnt, cent->currentState.powerups ); #ifdef _DEBUG //CG_Printf("Holster point %i drawn at %f %f %f (P.ORG %f %f %f)...\n", HOLSTER_POINT, holsterRefEnt.origin[0], holsterRefEnt.origin[1], holsterRefEnt.origin[2], cent->lerpOrigin[0], cent->lerpOrigin[1], cent->lerpOrigin[2]); #endif //_DEBUG } #ifdef _DEBUG else { //CG_Printf("Holster point %i NOT drawn...\n", HOLSTER_POINT); //assert(0); } #endif //_DEBUG } } }