bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) { // Get the entity because the weapon doesn't have the right angles. C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() ); if ( pEnt ) { if ( pEnt == C_BasePlayer::GetLocalPlayer() ) { vAngles = pEnt->EyeAngles(); } else { vAngles = pEnt->GetRenderAngles(); } } else { vAngles.Init(); } C_BasePlayer *player = ToBasePlayer( pEnt ); bool bUseViewModel = false; if ( C_BasePlayer::IsLocalPlayer( pEnt ) ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pEnt ); bUseViewModel = !player->ShouldDrawLocalPlayer(); } QAngle vDummy; if ( IsActiveByLocalPlayer() && bUseViewModel ) { C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { int iAttachment = vm->LookupAttachment( "muzzle" ); if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } } else { // Thirdperson int iAttachment = LookupAttachment( "muzzle" ); if ( GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } vOrigin = GetRenderOrigin(); return false; }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool C_BaseCombatWeapon::ShouldDraw( void ) { if ( m_iWorldModelIndex == 0 ) return false; // FIXME: All weapons with owners are set to transmit in CBaseCombatWeapon::UpdateTransmitState, // even if they have EF_NODRAW set, so we have to check this here. Ideally they would never // transmit except for the weapons owned by the local player. if ( IsEffectActive( EF_NODRAW ) ) return false; C_BaseCombatCharacter *pOwner = GetOwner(); // weapon has no owner, always draw it if ( !pOwner ) return true; bool bIsActive = ( m_iState == WEAPON_IS_ACTIVE ); C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); // carried by local player? if ( pOwner == pLocalPlayer ) { // Only ever show the active weapon if ( !bIsActive ) return false; if ( !pOwner->ShouldDraw() ) { // Our owner is invisible. // This also tests whether the player is zoomed in, in which case you don't want to draw the weapon. return false; } // 3rd person mode? if ( !ShouldDrawLocalPlayerViewModel() ) return true; // don't draw active weapon if not in some kind of 3rd person mode, the viewmodel will do that return false; } // If it's a player, then only show active weapons if ( pOwner->IsPlayer() ) { // Show it if it's active... return bIsActive; } // FIXME: We may want to only show active weapons on NPCs // These are carried by AIs; always show them return true; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_EntityFlame::UpdateHitBoxFlames( void ) { C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating) { return; } if (pAnimating->GetModel() != m_pCachedModel) { if (m_pCachedModel != NULL) { // The model changed, we must reattach the flames. DeleteHitBoxFlames(); AttachToHitBoxes(); } if (m_pCachedModel == NULL) { // We tried to reattach and failed. return; } } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } pAnimating->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime ); for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { Vector vecAbsOrigin; mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); VectorTransform(m_vecFireOrigin[i], pAnimating->GetBoneForWrite( pBox->bone ), vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); } }
bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) { // Get the entity because the weapon doesn't have the right angles. C_BaseCombatCharacter *pEnt = ToBaseCombatCharacter( GetOwner() ); if ( pEnt ) { if ( pEnt == C_BasePlayer::GetLocalPlayer() ) { vAngles = pEnt->EyeAngles(); } else { vAngles = pEnt->GetRenderAngles(); } } else { vAngles.Init(); } QAngle vDummy; if ( IsActiveByLocalPlayer() && !input->CAM_IsThirdPerson() ) { C_BasePlayer *player = ToBasePlayer( pEnt ); C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { int iAttachment = vm->LookupAttachment( "muzzle" ); if ( vm->GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } } else { // Thirdperson int iAttachment = LookupAttachment( "muzzle" ); if ( GetAttachment( iAttachment, vOrigin, vDummy ) ) { return true; } } vOrigin = GetRenderOrigin(); return false; }
//----------------------------------------------------------------------------- // Purpose: Attaches fire to the hitboxes of an animating character. The fire // is distributed based on hitbox volumes -- it attaches to the larger // hitboxes first. //----------------------------------------------------------------------------- void C_EntityFlame::AttachToHitBoxes( void ) { m_pCachedModel = NULL; C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating || !pAnimating->GetModel()) { return; } CStudioHdr *pStudioHdr = pAnimating->GetModelPtr(); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } m_pCachedModel = pAnimating->GetModel(); CBoneCache *pCache = pAnimating->GetBoneCache( pStudioHdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); // // Sort the hitboxes by volume. // HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; for ( int i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox(i); hitboxvolume[i].nIndex = i; hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); } qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); // // Attach fire to the hitboxes. // for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { int hitboxindex; // // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, // then pick random ones after that. // if (( i < 5 ) && ( i < set->numhitboxes )) { hitboxindex = i; } else { hitboxindex = random->RandomInt( 0, set->numhitboxes - 1 ); } mstudiobbox_t *pBox = set->pHitbox( hitboxvolume[hitboxindex].nIndex ); Assert( hitboxbones[pBox->bone] ); m_nHitbox[i] = hitboxvolume[hitboxindex].nIndex; m_pFireSmoke[i] = new C_FireSmoke; // // Calculate a position within the hitbox to place the fire. // m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); Vector vecAbsOrigin; VectorTransform( m_vecFireOrigin[i], *hitboxbones[pBox->bone], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); // // The first fire emits smoke, the rest do not. // m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE; m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); m_pFireSmoke[i]->m_nFlameFromAboveModelIndex = modelinfo->GetModelIndex("sprites/flamefromabove.vmt"); m_pFireSmoke[i]->m_flScale = 0; m_pFireSmoke[i]->m_flStartScale = 0; m_pFireSmoke[i]->m_flScaleTime = 1.5; m_pFireSmoke[i]->m_flScaleRegister = 0.1; m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; m_pFireSmoke[i]->m_flScaleStart = 0; m_pFireSmoke[i]->SetOwnerEntity( this ); // Do a simple That Looks About Right clamp on the volumes // so that we don't get flames too large or too tiny. float flVolume = hitboxvolume[hitboxindex].flVolume; Assert( IsFinite(flVolume) ); #define FLAME_HITBOX_MIN_VOLUME 1000.0f #define FLAME_HITBOX_MAX_VOLUME 4000.0f if( flVolume < FLAME_HITBOX_MIN_VOLUME ) { flVolume = FLAME_HITBOX_MIN_VOLUME; } else if( flVolume > FLAME_HITBOX_MAX_VOLUME ) { flVolume = FLAME_HITBOX_MAX_VOLUME; } m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * flVolume; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->StartClientOnly(); } m_bAttachedToHitboxes = true; }
//----------------------------------------------------------------------------- // Purpose: Attaches fire to the hitboxes of an animating character. The fire // is distributed based on hitbox volumes -- it attaches to the larger // hitboxes first. //----------------------------------------------------------------------------- void C_EntityFlame::AttachToHitBoxes( void ) { m_pCachedModel = NULL; C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating || !pAnimating->GetModel()) { return; } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } m_pCachedModel = pAnimating->GetModel(); int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); if ( !pcache ) { matrix3x4_t bonetoworld[MAXSTUDIOBONES]; pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); } matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); // // Sort the hitboxes by volume. // HitboxVolume_t hitboxvolume[MAXSTUDIOBONES]; for ( int i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox(i); hitboxvolume[i].nIndex = i; hitboxvolume[i].flVolume = CalcBoxVolume(pBox->bbmin, pBox->bbmax); } qsort(hitboxvolume, set->numhitboxes, sizeof(hitboxvolume[0]), (int (__cdecl *)(const void *, const void *))SortHitboxVolumes); // // Attach fire to the hitboxes. // for ( i = 0; i < NUM_HITBOX_FIRES; i++ ) { // // Pick the 5 biggest hitboxes, or random ones if there are less than 5 hitboxes, // then pick random ones after that. // if (( i < 5 ) && ( i < set->numhitboxes )) { m_nHitbox[i] = hitboxvolume[i].nIndex; } else { m_nHitbox[i] = random->RandomInt( 0, set->numhitboxes - 1 ); } mstudiobbox_t *pBox = set->pHitbox(m_nHitbox[i]); m_pFireSmoke[i] = new C_FireSmoke; // // Calculate a position within the hitbox to place the fire. // m_vecFireOrigin[i] = Vector(random->RandomFloat(pBox->bbmin.x, pBox->bbmax.x), random->RandomFloat(pBox->bbmin.y, pBox->bbmax.y), random->RandomFloat(pBox->bbmin.z, pBox->bbmax.z)); Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin( vecAbsOrigin ); // // The first 2 fires emit smoke, the rest do not. // m_pFireSmoke[i]->m_nFlags = bitsFIRESMOKE_ACTIVE | bitsFIRESMOKE_GLOW; if ( i < 2 ) { m_pFireSmoke[i]->m_nFlags |= bitsFIRESMOKE_SMOKE; } m_pFireSmoke[i]->m_nFlameModelIndex = modelinfo->GetModelIndex("sprites/fire1.vmt"); m_pFireSmoke[i]->m_flScale = 0; m_pFireSmoke[i]->m_flStartScale = 0; m_pFireSmoke[i]->m_flScaleTime = 1.5; m_pFireSmoke[i]->m_flScaleRegister = 0.1; m_pFireSmoke[i]->m_flChildFlameSpread = 20.0; m_pFireSmoke[i]->m_flScaleStart = 0; m_pFireSmoke[i]->m_flScaleEnd = 0.00012f * hitboxvolume[i].flVolume; m_pFireSmoke[i]->m_flScaleTimeStart = Helper_GetTime(); m_pFireSmoke[i]->m_flScaleTimeEnd = Helper_GetTime() + 2.0; m_pFireSmoke[i]->StartClientOnly(); } m_bAttachedToHitboxes = true; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_EntityFlame::UpdateHitBoxFlames( void ) { C_BaseCombatCharacter *pAnimating = (C_BaseCombatCharacter *)m_hEntAttached.Get(); if (!pAnimating) { return; } if (pAnimating->GetModel() != m_pCachedModel) { if (m_pCachedModel != NULL) { // The model changed, we must reattach the flames. DeleteHitBoxFlames(); AttachToHitBoxes(); } if (m_pCachedModel == NULL) { // We tried to reattach and failed. return; } } studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) { return; } mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->m_nHitboxSet ); if ( !set ) { return; } if ( !set->numhitboxes ) { return; } int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; studiocache_t *pcache = Studio_GetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask ); if ( !pcache ) { matrix3x4_t bonetoworld[MAXSTUDIOBONES]; pAnimating->SetupBones( bonetoworld, MAXSTUDIOBONES, boneMask, gpGlobals->curtime ); pcache = Studio_SetBoneCache( pStudioHdr, pAnimating->GetSequence(), pAnimating->m_flAnimTime, pAnimating->GetAbsAngles(), pAnimating->GetAbsOrigin(), boneMask, bonetoworld ); } matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; Studio_LinkHitboxCache( hitboxbones, pcache, pStudioHdr, set ); for ( int i = 0; i < NUM_HITBOX_FIRES; i++ ) { Vector vecAbsOrigin; VectorTransform(m_vecFireOrigin[i], *hitboxbones[m_nHitbox[i]], vecAbsOrigin); m_pFireSmoke[i]->SetLocalOrigin(vecAbsOrigin); } }