void CTFBotVision::Update() { if (TFGameRules()->IsMannVsMachineMode()) { if (!this->m_ctUpdate.IsElapsed()) { return; } this->m_ctUpdate.Start(RandomFloat(0.9f, 1.1f)); } IVision::Update(); CTFBot *actor = static_cast<CTFBot *>(this->GetBot()->GetEntity()); if (actor == nullptr) { return; } CUtlVector<CTFPlayer *> enemies; CollectPlayers<CTFPlayer>(enemies, GetEnemyTeam(actor), true, false); FOR_EACH_VEC(enemies, i) { CTFPlayer *enemy = enemies[i]; if (enemy->IsPlayerClass(TF_CLASS_SPY)) { const CKnownEntity *known = this->GetKnown(enemy); if (known != nullptr && (known->IsVisibleRecently() || !player->m_Shared.InCond(TF_COND_DISGUISING))) { actor->ForgetSpy(enemy); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGameMovement::PlayerRoughLandingEffects( float fvol ) { if ( m_pTFPlayer && m_pTFPlayer->IsPlayerClass(TF_CLASS_SCOUT) ) { // Scouts don't play rumble unless they take damage. if ( fvol < 1.0 ) { fvol = 0; } } BaseClass::PlayerRoughLandingEffects( fvol ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponSpawner::EndTouch( CBaseEntity *pOther ) { CTFPlayer *pTFPlayer = dynamic_cast<CTFPlayer*>( pOther ); if ( ValidTouch( pTFPlayer ) && pTFPlayer->IsPlayerClass( TF_CLASS_MERCENARY ) ) { int iCurrentWeaponID = pTFPlayer->m_Shared.GetDesiredWeaponIndex(); if ( iCurrentWeaponID == m_nItemID ) { pTFPlayer->m_Shared.SetDesiredWeaponIndex( -1 ); } } }
bool CTFRevolver::DefaultReload( int iClipSize1, int iClipSize2, int iActivity ) { // The the owning local player. CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( !pPlayer ) return false; if ( pPlayer->IsPlayerClass( TF_CLASS_SPY ) ) { if ( pPlayer->m_Shared.InCond( TF_COND_STEALTHED ) ) { return false; } } return BaseClass::DefaultReload( iClipSize1, iClipSize2, iActivity ); }
/* make the targeted player known to all bots even if not in their ordinary * vision range; and if they're a spy, reveal their identity */ void NotifyBotsAboutTarget() { for (int i = 1; i <= gpGlobals->maxClients; ++i) { CTFPlayer *player = ToTFPlayer(UTIL_PlayerByIndex(i)); if (player == nullptr || !IsTheTarget(player)) continue; for (int j = 1; j <= gpGlobals->maxClients; ++j) { CTFBot *bot = ToTFBot(UTIL_PlayerByIndex(j)); if (bot == nullptr || bot->GetTeamNumber() != TF_TEAM_BLUE) continue; if (player->IsPlayerClass(TF_CLASS_SPY)) { bot->RealizeSpy(player); } bot->GetVisionInterface()->AddKnownEntity(player); } } }
//----------------------------------------------------------------------------- // Purpose: Set the owner's weapon and last weapon appropriately when we need to // switch away from the builder weapon. //----------------------------------------------------------------------------- void CTFWeaponBuilder::SwitchOwnersWeaponToLast() { CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); if ( !pOwner ) return; // for engineer, switch to wrench and set last weapon appropriately if ( pOwner->IsPlayerClass( TF_CLASS_ENGINEER ) ) { // Switch to wrench if possible. if not, then best weapon CBaseCombatWeapon *pWpn = pOwner->Weapon_GetSlot( 2 ); // Don't store last weapon when we autoswitch off builder CBaseCombatWeapon *pLastWpn = pOwner->Weapon_GetLast(); if ( pWpn ) { pOwner->Weapon_Switch( pWpn ); } else { pOwner->SwitchToNextBestWeapon( NULL ); } if ( pWpn == pLastWpn ) { // We had the wrench out before we started building. Go ahead and set out last // weapon to our primary weapon. pWpn = pOwner->Weapon_GetSlot( 0 ); pOwner->Weapon_SetLast( pWpn ); } else { pOwner->Weapon_SetLast( pLastWpn ); } } else { // for all other classes, just switch to last weapon used pOwner->Weapon_Switch( pOwner->Weapon_GetLast() ); } }
void CTFPowerupBottle::ReapplyProvision() { CTFWearable::ReapplyProvision(); CBaseEntity *owner = this->GetOwnerEntity(); if (owner == nullptr) { return; } IHasAttributes *owner_ihasattr = owner->GetHasAttributesInterfacePtr(); if (owner_ihasattr == nullptr) { return; } if (this->m_bActive) { if (!owner_ihasattr->GetAttributeManager()->IsBeingProvidedToBy(this)) { this->GetAttributeManager()->ProvideTo(owner); } } else { this->GetAttributeManager()->StopProvidingTo(owner); } CTFPlayer *player = dynamic_cast<CTFPlayer *>(owner); if (player == nullptr) { return; } /* BUG: because "canteen_specialist" is an integer attribute, the call to * AttribHookValue<int> will truncate any fractional part of the powerup * duration */ float duration = CAttributeManager::AttribHookValue<float>(0.0f, "powerup_duration", this, nullptr, true); duration = CAttributeManager::AttribHookValue<int>((int)duration, "canteen_specialist", player, nullptr, true); CTFPlayer *share_with = nullptr; int share_attr = 0; if (player->IsPlayerClass(TF_CLASS_MEDIC)) { CTFWeaponBase *weapon = player->GetActiveWeapon(); if (weapon != nullptr) { CWeaponMedigun *medigun = dynamic_cast<CWeaponMedigun *>(weapon); if (medigun != nullptr) { share_with = ToTFPlayer(medigun->GetHealTarget()); if (share_with != nullptr) { share_attr = CAttributeManager::AttribHookValue<int>(0, "canteen_specialist", player, nullptr, true); } } } } bool did_share = false; if (CAttributeManager::AttribHookValue<int>(0, "critboost", this, nullptr, true) != 0) { if (this->m_bActive) { player->m_Shared.AddCond(TF_COND_CRITBOOSTED_USER_BUFF, duration); if (share_with != nullptr && share_attr != 0) { share_with->m_Shared.AddCond(TF_COND_CRITBOOSTED_USER_BUFF, duration); did_share = true; } } else { player->m_Shared.RemoveCond(TF_COND_CRITBOOSTED_USER_BUFF, true); } } if (CAttributeManager::AttribHookValue<int>(0, "ubercharge", this, nullptr, true) != 0) { if (this->m_bActive) { player->m_Shared.AddCond(TF_COND_INVULNERABLE_USER_BUFF, duration); if (player->IsPlayerClass(TF_CLASS_ENGINEER)) { int obj_count = player->GetObjectCount(); if (obj_count > 0) { for (int i = obj_count - 1; i != -1; --i) { CBaseObject *obj = player->GetObject(i); if (obj != nullptr) { CObjectSentrygun *sentry = dynamic_cast<CObjectSentrygun *>(obj); if (sentry != nullptr && !sentry->m_bCarried) { sentry->m_nShieldLevel = 2; // TODO: set float @ CObjectSentrygun+0xb14 // to gpGlobals->curtime + duration } } } } } else if (share_with != nullptr && share_attr != 0) { share_with->m_Shared.AddCond(TF_COND_INVULNERABLE_USER_BUFF, duration); did_share = true; } } else { player->m_Shared.RemoveCond(TF_COND_INVULNERABLE_USER_BUFF, true); } } if (CAttributeManager::AttribHookValue<int>(0, "recall", this, nullptr, true) != 0) { if (this->m_bActive) { player->ForceRespawn(); player->m_Shared.AddCond(TF_COND_SPEED_BOOST, 7.0f); } } if (CAttributeManager::AttribHookValue<int>(0, "refill_ammo", this, nullptr, true) != 0) { if (this->m_bActive) { for (int i = 0; i < MAX_WEAPONS; ++i) { CBaseCombatWeapon *weapon = player->GetWeapon(i); if (weapon == nullptr) { continue; } /* BUG: as soon as this loop hits a weapon which is completely * devoid of ammo (clip 0, reserve 0), it will * (a) fail to refill the clip for that weapon, and * (b) fail to refill the clip for any weapons in later slots * NOTE: for the purposes of this, energy weapons are treated as * if their reserve ammo is always empty */ if (TFGameRules() != nullptr && TFGameRules()->IsMannVsMachineMode() && ((weapon->UsesPrimaryAmmo() && !weapon->HasPrimaryAmmo()) || (weapon->UsesSecondaryAmmo() && !weapon->HasSecondaryAmmo()))) { player->AwardAchievement(TF_MVM_USE_AMMO_BOTTLE); break; } /* BUG: doesn't refill clip of energy weapons * (should vcall weapon->IsEnergyWeapon, * then call weapon->Energy_Recharge * until weapon->Energy_FullyCharged) */ // CBaseCombatWeapon::UsesPrimaryAmmo: // - if m_iPrimaryAmmoType < 0: return false // - else: return true // CBaseCombatWeapon::UsesSecondaryAmmo: // - if m_iSecondaryAmmoType < 0: return false // - else: return true // CTFWeaponBaseGun::HasPrimaryAmmo: // - there's a special case if m_iPrimaryAmmoType == TF_AMMO_METAL (e.g. Widowmaker) // - if UsesClipsForAmmo1(): return (m_iClip1 > 0) || (pOwner->GetAmmoCount(m_iPrimaryAmmoType) > 0) // - else: return (pOwner->GetAmmoCount(m_iPrimaryAmmoType) > 0) // CBaseCombatWeapon::HasSecondaryAmmo: // - if UsesClipsForAmmo1(): return (m_iClip2 > 0) || (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0) // - else: return (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0) weapon->GiveDefaultAmmo(); if (share_with != nullptr && share_attr != 0) { CBaseCombatWeapon *share_weapon = share_with->GetWeapon(i); if (share_weapon != nullptr) { share_weapon->GiveDefaultAmmo(); did_share = true; } } } /* NOTE: invented TF_AMMO_SOURCE_RESUPPLY for (EAmmoSource)1 */ if (share_with != nullptr && share_attr != 0) { for (int i = 0; i < TF_AMMO_COUNT; ++i) { player->GiveAmmo(player->GetMaxAmmo(i), i, true, TF_AMMO_SOURCE_RESUPPLY); share_with->GiveAmmo(share_with->GetMaxAmmo(i), i, true, TF_AMMO_SOURCE_RESUPPLY); } did_share = true; } else { for (int i = 0; i < TF_AMMO_COUNT; ++i) { player->GiveAmmo(player->GetMaxAmmo(i), i, true, TF_AMMO_SOURCE_RESUPPLY); } } } } if (CAttributeManager::AttribHookValue<int>(0, "building_instant_upgrade", this, nullptr, true) != 0) { if (this->m_bActive) { int obj_count = player->GetObjectCount(); if (obj_count > 0) { for (int i = obj_count - 1; i != -1; --i) { CBaseObject *obj = player->GetObject(i); if (obj != nullptr) { int max_level = obj->GetMaxUpgradeLevel(); if (obj->m_bCarried) { /* BUG: this can't possibly be right */ obj->m_iHighestUpgradeLevel = obj->GetMaxUpgradeLevel(); } else if (obj->GetUpgradeLevel() == max_level) { obj->SetHealth(obj->GetMaxHealth()); } else { if (TFGameRules() && TFGameRules()->IsMannVsMachineMode()) { // TODO: event mvm_quick_sentry_upgrade } obj->DoQuickBuild(true); } } } } } } if (did_share) { // TODO: event mvm_medic_powerup_shared } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFDroppedWeapon::MyTouch( CBasePlayer *pPlayer ) { bool bSuccess = false; CTFPlayer *pTFPlayer = dynamic_cast<CTFPlayer *>( pPlayer ); if ( ValidTouch( pTFPlayer ) && pTFPlayer->IsPlayerClass( TF_CLASS_MERCENARY ) ) { // Don't remove weapon while a player is standing over it. SetThink( NULL ); #ifndef DM_WEAPON_BUCKET int iSlot = m_Item.GetStaticData()->GetLoadoutSlot( TF_CLASS_MERCENARY ); CTFWeaponBase *pWeapon = (CTFWeaponBase *)pTFPlayer->GetEntityForLoadoutSlot( iSlot ); const char *pszWeaponName = m_Item.GetEntityName(); int iAmmoType = m_pWeaponInfo->iAmmoType; if ( pWeapon ) { if ( pWeapon->GetItemID() == m_Item.GetItemDefIndex() ) { // Give however many ammo we have if ( pTFPlayer->GiveAmmo( m_iAmmo, iAmmoType, true, TF_AMMO_SOURCE_AMMOPACK ) ) bSuccess = true; } else if ( !(pTFPlayer->m_nButtons & IN_ATTACK) && ( pTFPlayer->m_nButtons & IN_USE ) ) // Check Use button { // Drop a usable weapon pTFPlayer->DropWeapon( pWeapon ); if ( pWeapon == pTFPlayer->GetActiveTFWeapon() ) { pWeapon->Holster(); } pTFPlayer->Weapon_Detach( pWeapon ); UTIL_Remove( pWeapon ); pWeapon = NULL; } else { pTFPlayer->m_Shared.SetDesiredWeaponIndex( m_Item.GetItemDefIndex() ); } } #else CTFWeaponBase *pWeapon = pTFPlayer->Weapon_OwnsThisID( m_nWeaponID ); if ( pWeapon ) { if ( pTFPlayer->GiveAmmo( 999, GetTFWeaponInfo( m_nWeaponID )->iAmmoType ) ); bSuccess = true; } #endif if ( !pWeapon ) { CTFWeaponBase *pNewWeapon = (CTFWeaponBase *)pTFPlayer->GiveNamedItem( pszWeaponName, 0, &m_Item ); if ( pNewWeapon ) { pPlayer->SetAmmoCount( m_iAmmo, iAmmoType ); pNewWeapon->DefaultTouch( pPlayer ); if ( pPlayer == GetOwnerEntity() ) { // If this is the same guy who dropped it restore old clip size to avoid exploiting swapping // weapons for faster reload. pNewWeapon->m_iClip1 = m_iClip; } pTFPlayer->m_Shared.SetDesiredWeaponIndex( -1 ); bSuccess = true; } } if ( bSuccess ) { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); UserMessageBegin( user, "ItemPickup" ); WRITE_STRING( GetClassname() ); MessageEnd(); pPlayer->EmitSound( "BaseCombatCharacter.AmmoPickup" ); } } return bSuccess; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponMedigun::UpdateEffects( void ) { CTFPlayer *pFiringPlayer = ToTFPlayer( GetOwnerEntity() ); if ( !pFiringPlayer ) return; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); C_BaseEntity *pEffectOwner = this; if ( pLocalPlayer == pFiringPlayer ) { pEffectOwner = pLocalPlayer->GetViewModel(); if ( !pEffectOwner ) return; } // Remove all the effects if ( pEffectOwner ) { pEffectOwner->ParticleProp()->StopEmission( m_hHealingTargetEffect.pEffect ); } else { m_hHealingTargetEffect.pEffect->StopEmission(); } m_hHealingTargetEffect.pTarget = NULL; m_hHealingTargetEffect.pEffect = NULL; // Don't add targets if the medic is dead if ( !pEffectOwner || pFiringPlayer->IsPlayerDead() || !pFiringPlayer->IsPlayerClass( TF_CLASS_MEDIC ) ) return; // Add our targets // Loops through the healing targets, and make sure we have an effect for each of them if ( m_hHealingTarget ) { if ( m_hHealingTargetEffect.pTarget == m_hHealingTarget ) return; const char *pszEffectName; if (m_bChargeRelease) { switch (GetTeamNumber()) { case TF_TEAM_BLUE: pszEffectName = "medicgun_beam_blue_invun"; break; case TF_TEAM_RED: pszEffectName = "medicgun_beam_red_invun"; break; case TF_TEAM_GREEN: pszEffectName = "medicgun_beam_green_invun"; break; case TF_TEAM_YELLOW: pszEffectName = "medicgun_beam_yellow_invun"; break; default: pszEffectName = "medicgun_beam_blue"; break; } } else { switch (GetTeamNumber()) { case TF_TEAM_BLUE: pszEffectName = "medicgun_beam_blue"; break; case TF_TEAM_RED: pszEffectName = "medicgun_beam_red"; break; case TF_TEAM_GREEN: pszEffectName = "medicgun_beam_green"; break; case TF_TEAM_YELLOW: pszEffectName = "medicgun_beam_yellow"; break; default: pszEffectName = "medicgun_beam_blue"; break; } } CNewParticleEffect *pEffect = pEffectOwner->ParticleProp()->Create( pszEffectName, PATTACH_POINT_FOLLOW, "muzzle" ); pEffectOwner->ParticleProp()->AddControlPoint( pEffect, 1, m_hHealingTarget, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector(0,0,50) ); m_hHealingTargetEffect.pTarget = m_hHealingTarget; m_hHealingTargetEffect.pEffect = pEffect; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CWeaponSpawner::MyTouch( CBasePlayer *pPlayer ) { bool bSuccess = false; CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer ); if ( ValidTouch( pTFPlayer ) && pTFPlayer->IsPlayerClass( TF_CLASS_MERCENARY ) ) { #ifndef DM_WEAPON_BUCKET int iSlot = m_Item.GetStaticData()->GetLoadoutSlot( TF_CLASS_MERCENARY ); CTFWeaponBase *pWeapon = (CTFWeaponBase *)pTFPlayer->GetEntityForLoadoutSlot( iSlot ); if ( pWeapon ) { if ( pTFPlayer->ItemsMatch( pWeapon->GetItem(), &m_Item, pWeapon ) ) { if ( pTFPlayer->GiveAmmo( pWeapon->GetInitialAmmo(), pWeapon->GetPrimaryAmmoType(), true, TF_AMMO_SOURCE_AMMOPACK ) ) bSuccess = true; } else if ( !( pTFPlayer->m_nButtons & IN_ATTACK ) && ( pTFPlayer->m_nButtons & IN_USE || ( TFGameRules()->IsDeathmatch() && pWeapon->GetWeaponID() == TF_WEAPON_PISTOL ) ) ) // Check Use button, always replace pistol. { // Drop a usable weapon pTFPlayer->DropWeapon( pWeapon ); pWeapon->UnEquip( pTFPlayer ); pWeapon = NULL; } else { pTFPlayer->m_Shared.SetDesiredWeaponIndex( m_nItemID ); } } #else CTFWeaponBase *pWeapon = pTFPlayer->Weapon_OwnsThisID( m_nWeaponID ); const char *pszWeaponName = WeaponIdToClassname( m_nWeaponID ); if ( pWeapon ) { if ( pPlayer->GiveAmmo(999, m_pWeaponInfo->iAmmoType) ) bSuccess = true; } #endif if ( !pWeapon ) { const char *pszWeaponName = m_Item.GetEntityName(); CTFWeaponBase *pNewWeapon = (CTFWeaponBase *)pTFPlayer->GiveNamedItem( pszWeaponName, 0, &m_Item ); if ( pNewWeapon ) { pPlayer->SetAmmoCount( pNewWeapon->GetInitialAmmo(), pNewWeapon->GetPrimaryAmmoType() ); pNewWeapon->GiveTo( pPlayer ); pTFPlayer->m_Shared.SetDesiredWeaponIndex( -1 ); bSuccess = true; } } if ( bSuccess ) { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); UserMessageBegin( user, "ItemPickup" ); WRITE_STRING( GetClassname() ); MessageEnd(); pPlayer->EmitSound( "BaseCombatCharacter.AmmoPickup" ); } } return bSuccess; }