//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_BaseObject::Simulate( void )
{
	if ( IsPlacing() && !MustBeBuiltOnAttachmentPoint() )
	{
		int iValidPlacement = ( IsPlacementPosValid() && ServerValidPlacement() ) ? 1 : 0;

		if ( m_iLastPlacementPosValid != iValidPlacement )
		{
			m_iLastPlacementPosValid = iValidPlacement;
			OnPlacementStateChanged( m_iLastPlacementPosValid > 0 );
		}

		// We figure out our own placement pos, but we still leave it to the server to 
		// do collision with other entities and nobuild triggers, so that sets the 
		// placement animation

		SetLocalOrigin( m_vecBuildOrigin );
		InvalidateBoneCache();

		// Clear out our origin and rotation interpolation history
		// so we don't pop when we teleport in the actual position from the server

		CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
		interpolator.ClearHistory();

		CInterpolatedVar<QAngle> &rotInterpolator = GetRotationInterpolator();
		rotInterpolator.ClearHistory();
	}	

	BaseClass::Simulate();
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this object should be active
//-----------------------------------------------------------------------------
bool CBaseObject::ShouldBeActive( void )
{
	// Placing and/or constructing objects shouldn't be active
	if ( IsPlacing() || IsBuilding() )
		return false;

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Find nearby objects and buff them.
//-----------------------------------------------------------------------------
void CObjectBuffStation::BuffNearbyObjects( CBaseObject *pObjectToTarget, bool bPlacing )
{
	// ROBIN: Disabled object buffing for now
	return;

	// Check for a team.
	if ( !GetTFTeam() )
		return;

	// Am I ready to power anything?
	if ( IsBuilding() || ( !bPlacing && IsPlacing() ) )
		return;

	// Am I already full?
	if ( m_nObjectCount >= BUFF_STATION_MAX_OBJECTS )
		return;

	// Do we have a specific target?
	if ( pObjectToTarget )
	{
		if( !pObjectToTarget->CanBeHookedToBuffStation() || pObjectToTarget->GetBuffStation() )
			return;

		if ( IsWithinBuffRange( pObjectToTarget ) )
		{
			AttachObject( pObjectToTarget, bPlacing );
		}
	}
	else
	{
		// Find nearby objects 
		for ( int iObject = 0; iObject < GetTFTeam()->GetNumObjects(); iObject++ )
		{
			CBaseObject *pObject = GetTFTeam()->GetObject( iObject );
			assert(pObject);

			if ( pObject == this || !pObject->CanBeHookedToBuffStation() || pObject->GetBuffStation() )
				continue;

			// Make sure it's within range
			if ( IsWithinBuffRange( pObject ) )
			{
				AttachObject( pObject, bPlacing );

				// Am I now full?
				if ( m_nObjectCount >= BUFF_STATION_MAX_OBJECTS )
					break;
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Change our model based on the object we are attaching to
//-----------------------------------------------------------------------------
void CObjectSapper::SetupAttachedVersion( void )
{
	CBaseObject *pObject = dynamic_cast<CBaseObject *>( m_hBuiltOnEntity.Get() );

	Assert( pObject );

	if ( !pObject )
	{
		DestroyObject();
		return;
	}

	if ( IsPlacing() )
	{
		SetModel( GetSapperModelName( SAPPER_MODEL_PLACEMENT ) );
	}	

	BaseClass::SetupAttachedVersion();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBuffStation::BoostObjectThink( void )
{
	// Set next boost object think time.
	SetNextThink( gpGlobals->curtime + BUFF_STATION_BOOST_OBJECT_THINK_INTERVAL, 
		          BUFF_STATION_BOOST_OBJECT_THINK_CONTEXT );

	// If we're emped, placing, or building, we're not ready to powerup
	if ( IsPlacing() || IsBuilding() || HasPowerup( POWERUP_EMP ) )
		return;

	float flMaxRangeSq = obj_buff_station_obj_range.GetFloat();
	flMaxRangeSq *= flMaxRangeSq;

	// Boost objects.
	for ( int iObject = m_nObjectCount; --iObject >= 0; )
	{
		CBaseObject *pObject = m_hObjects[iObject].Get();
		if ( !pObject || !InSameTeam( pObject ) )
		{
			DetachObjectByIndex( iObject );
			continue;
		}

		// Check for out of range.
		float flDistSq = GetAbsOrigin().DistToSqr( pObject->GetAbsOrigin() ); 
		if ( flDistSq > flMaxRangeSq )
		{
			DetachObjectByIndex( iObject );
			continue;
		}

		// Don't powerup it until it's finished building
		if ( pObject->IsPlacing() || pObject->IsBuilding() )
			continue;

		// Boost it
		if ( !pObject->AttemptToPowerup( POWERUP_BOOST, BUFF_STATION_BOOST_OBJECT_THINK_INTERVAL, 0, 
			                                  this, &m_aObjectAttachInfo[iObject].m_DamageModifier ) )
		{
			m_aObjectAttachInfo[iObject].m_DamageModifier.RemoveModifier();
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CBaseTFVehicle::VehiclePassengerThink( void )
{
	SetNextThink( gpGlobals->curtime + 10.0, PASSENGER_THINK_CONTEXT );

	if ( IsPlacing() )
	{
		ResetDeteriorationTime();
		return;
	}

	// If there are any passengers in the vehicle, push off deterioration time
	if ( GetPassengerCount() )
	{
		ResetDeteriorationTime();
		return;
	}

	// See if there are any team members nearby
	if ( GetTeam() )
	{
		int iNumPlayers = GetTFTeam()->GetNumPlayers();
		for ( int i = 0; i < iNumPlayers; i++ )
		{
			if ( GetTFTeam()->GetPlayer(i) )
			{
				Vector vecOrigin = GetTFTeam()->GetPlayer(i)->GetAbsOrigin();
				if ( (vecOrigin - GetAbsOrigin()).LengthSqr() < DETERIORATION_DISTANCE )
				{
					// Found one nearby, reset our deterioration time
					ResetDeteriorationTime();
					return;
				}
			}
		}
	}
}
void CObjectTeleporter::DeterminePlaybackRate( void )
{
	float flPlaybackRate = GetPlaybackRate();

	bool bWasBelowFullSpeed = ( flPlaybackRate < 1.0f );

	if ( IsBuilding() )
	{
		// Default half rate, author build anim as if one player is building
		SetPlaybackRate( GetConstructionMultiplier() * 0.5 );	
	}
	else if ( IsPlacing() )
	{
		SetPlaybackRate( 1.0f );
	}
	else
	{
		float flFrameTime = 0.1;	// BaseObjectThink delay

		switch( m_iState )
		{
		case TELEPORTER_STATE_READY:	
			{
				// spin up to 1.0 from whatever we're at, at some high rate
				flPlaybackRate = Approach( 1.0f, flPlaybackRate, 0.5f * flFrameTime );
			}
			break;

		case TELEPORTER_STATE_RECHARGING:
			{
				// Recharge - spin down to low and back up to full speed over 10 seconds

				// 0 -> 4, spin to low
				// 4 -> 6, stay at low
				// 6 -> 10, spin to 1.0

				float flScale = g_flTeleporterRechargeTimes[GetUpgradeLevel() - 1] / g_flTeleporterRechargeTimes[0];
				
				float flToLow = 4.0f * flScale;
				float flToHigh = 6.0f * flScale;
				float flRechargeTime = g_flTeleporterRechargeTimes[GetUpgradeLevel() - 1];

				float flTimeSinceChange = gpGlobals->curtime - m_flLastStateChangeTime;

				float flLowSpinSpeed = 0.15f;

				if ( flTimeSinceChange <= flToLow )
				{
					flPlaybackRate = RemapVal( gpGlobals->curtime,
						m_flLastStateChangeTime,
						m_flLastStateChangeTime + flToLow,
						1.0f,
						flLowSpinSpeed );
				}
				else if ( flTimeSinceChange > flToLow && flTimeSinceChange <= flToHigh )
				{
					flPlaybackRate = flLowSpinSpeed;
				}
				else
				{
					flPlaybackRate = RemapVal( gpGlobals->curtime,
						m_flLastStateChangeTime + flToHigh,
						m_flLastStateChangeTime + flRechargeTime,
						flLowSpinSpeed,
						1.0f );
				}
			}		
			break;

		default:
			{
				if ( m_flLastStateChangeTime <= 0.0f )
				{
					flPlaybackRate = 0.0f;
				}
				else
				{
					// lost connect - spin down to 0.0 from whatever we're at, slowish rate
					flPlaybackRate = Approach( 0.0f, flPlaybackRate, 0.25f * flFrameTime );
				}
			}
			break;
		}

		SetPlaybackRate( flPlaybackRate );
	}

	bool bBelowFullSpeed = ( GetPlaybackRate() < 1.0f );

	if ( m_iBlurBodygroup >= 0 && bBelowFullSpeed != bWasBelowFullSpeed )
	{
		if ( bBelowFullSpeed )
		{
			SetBodygroup( m_iBlurBodygroup, 0 );	// turn off blur bodygroup
		}
		else
		{
			SetBodygroup( m_iBlurBodygroup, 1 );	// turn on blur bodygroup
		}
	}

	StudioFrameAdvance();
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_BaseObject::OnDataChanged( DataUpdateType_t updateType )
{
	if (updateType == DATA_UPDATE_CREATED)
	{
		CreateBuildPoints();
	}

	BaseClass::OnDataChanged( updateType );

	// Did we just finish building?
	if ( m_bWasBuilding && !m_bBuilding )
	{
		FinishedBuilding();
	}

	// Did we just go active?
	bool bShouldBeActive = ShouldBeActive();
	if ( !m_bWasActive && bShouldBeActive )
	{
		OnGoActive();
	}
	else if ( m_bWasActive && !bShouldBeActive )
	{
		OnGoInactive();
	}

	if ( m_bDisabled != m_bOldDisabled )
	{
		if ( m_bDisabled )
		{
			OnStartDisabled();
		}
		else
		{
			OnEndDisabled();
		}
	}

	if ( ( !IsBuilding() && m_iHealth != m_iOldHealth ) )
	{
		// recalc our damage particle state
		BuildingDamageLevel_t damageLevel = CalculateDamageLevel();

		if ( damageLevel != m_damageLevel )
		{
			UpdateDamageEffects( damageLevel );

			m_damageLevel = damageLevel;
		}
	}

	if ( m_bWasBuilding && !m_bBuilding )
	{
		// Force update damage effect when finishing construction.
		BuildingDamageLevel_t damageLevel = CalculateDamageLevel();
		UpdateDamageEffects( damageLevel );
		m_damageLevel = damageLevel;
	}

	// Kill all particles when getting picked up.
	if ( !m_bWasCarried && m_bCarried )
	{
		ParticleProp()->StopParticlesInvolving( this );
	}

	if ( m_iHealth > m_iOldHealth && m_iHealth == m_iMaxHealth )
	{
		// If we were just fully healed, remove all decals
		RemoveAllDecals();
	}

	if ( GetOwner() == C_TFPlayer::GetLocalTFPlayer() )
	{
		IGameEvent *event = gameeventmanager->CreateEvent( "building_info_changed" );
		if ( event )
		{
			event->SetInt( "building_type", GetType() );
			event->SetInt( "object_mode", GetObjectMode() );
			gameeventmanager->FireEventClientSide( event );
		}
	}

	if ( IsPlacing() && GetSequence() != m_nObjectOldSequence )
	{
		// Ignore server sequences while placing
		OnPlacementStateChanged( m_iLastPlacementPosValid > 0 );
	}
}
void C_ObjectSentrygun::ClientThink( void )
{
	// Turtling sentryguns don't think
	if ( IsTurtled() )
		return;

	if ( IsPlacing() || IsBuilding() )
		return;


	if ( m_hEnemy != NULL )
	{
		// Figure out where we're firing at
		Vector vecMid = EyePosition();
		Vector vecFireTarget = m_hEnemy->WorldSpaceCenter(); //  + vecMid; // BodyTarget( vecMid );
		Vector vecDirToEnemy = vecFireTarget - vecMid;
		QAngle angToTarget;
		VectorAngles(vecDirToEnemy, angToTarget);
		
		angToTarget.y = UTIL_AngleMod( angToTarget.y );
		if (angToTarget.x < -180)
			angToTarget.x += 360;
		if (angToTarget.x > 180)
			angToTarget.x -= 360;

		// now all numbers should be in [1...360]
		// pin to turret limitations to [-50...50]
		if (angToTarget.x > 50)
			angToTarget.x = 50;
		else if (angToTarget.x < -50)
			angToTarget.x = -50;

		m_vecGoalAngles.y = angToTarget.y;
		m_vecGoalAngles.x = angToTarget.x;

		MoveTurret();
		return;
	}

	// Rotate
	if ( !MoveTurret() )
	{
		// Play a sound occasionally
		if ( random->RandomFloat(0, 1) < 0.02 )
		{
			EmitSound( "ObjectSentrygun.Idle" );
		}

		// Switch rotation direction
		if (m_bTurningRight)
		{
			m_bTurningRight = false;
			m_vecGoalAngles.y = m_iLeftBound;
		}
		else
		{
			m_bTurningRight = true;
			m_vecGoalAngles.y = m_iRightBound;
		}

		// Randomly look up and down a bit
		if ( random->RandomFloat(0, 1) < 0.3 )
		{
			m_vecGoalAngles.x = (int)random->RandomFloat(-10,10);
		}
	}
}
Exemple #10
0
//-----------------------------------------------------------------------------
// Purpose: Change our model based on the object we are attaching to
//-----------------------------------------------------------------------------
void CObjectSapper::SetupAttachedVersion( void )
{
	CBaseObject *pObject = dynamic_cast<CBaseObject *>( m_hBuiltOnEntity.Get() );

	Assert( pObject );

	if ( !pObject )
	{
		DestroyObject();
		return;
	}

	if ( IsPlacing() )
	{
		switch( pObject->GetType() )
		{
		case OBJ_SENTRYGUN:
			{
				// what level?
				CObjectSentrygun *pSentry = dynamic_cast<CObjectSentrygun *>( pObject );
				Assert( pSentry );
				if ( !pSentry )
				{
					DestroyObject();
					return;
				}

				int iLevel = pSentry->GetUpgradeLevel();

				switch( iLevel )
				{
				case 1:
					SetModel( SAPPER_MODEL_SENTRY_1_PLACEMENT );
					break;
				case 2:
					SetModel( SAPPER_MODEL_SENTRY_2_PLACEMENT );
					break;
				case 3:
					SetModel( SAPPER_MODEL_SENTRY_3_PLACEMENT );
					break;
				default:
					Assert(0);
					break;
				}
			}
			break;

		case OBJ_TELEPORTER:
			SetModel( SAPPER_MODEL_TELEPORTER_PLACEMENT );
			break;

		case OBJ_DISPENSER:
			SetModel( SAPPER_MODEL_DISPENSER_PLACEMENT );
			break;

		default:
			Assert( !"what kind of object are we trying to place a sapper on?" );
			break;
		}
	}	

	BaseClass::SetupAttachedVersion();
}