Beispiel #1
0
//------------------------------------------------------------------
//
//   FUNCTION : UpdateInstanceInterval()
//
//   PURPOSE  : Given an instance and a time interval, this will appropriately update
//				all effects contained within that interval
//
//------------------------------------------------------------------
void CClientFXMgr::UpdateInstanceInterval(CLIENTFX_INSTANCE* pInst, float fStartInterval, float fEndInterval)
{
	//here are the possible scenarios:
	// Inactive
	// Inactive -> Active -> Shutting down
	// Inactive -> Active -> Shutting down -> Inactive
	// Inactive -> Active
	// Shutting Down
	// Shutting Down -> Inactive
	// Shutting Down -> Active -> Shutting Down
	// Shutting Down -> Active -> Shutting Down -> Inactive
	// Shutting Down -> Active
	// Active

	//A note about intervals: The interval used is inclusive of both start and ends. This does
	//mean that a boundary such as a key beginning or end can be hit twice, but because of the
	//way the state flow works, this will not cause any issues, since when it is inactive
	//it will look for active and vice a versa. Therefore since the beginning and end cannot
	//lie on the same position this should not introduce any issues, but ensures that the
	//full track length is handled when updating

	//alright, run through all active effects and determine what to do
	CLinkListNode<FX_LINK>				*pActiveNode;
	CLinkListNode<FX_LINK>				*pNextActiveNode;

	//determine if this is a looping instance
	bool bLoopInstance = pInst->m_bLoop;

	pActiveNode = pInst->m_collActiveFX.GetHead();
	while( pActiveNode )
	{
		//cache the next node in case we delete this key
		pNextActiveNode = pActiveNode->m_pNext;

		//alright, first off look at the state of the key and see what to do
		CBaseFX	*pFX		= pActiveNode->m_Data.m_pFX;
		const FX_KEY* pKey	= pActiveNode->m_Data.m_pRef;

		//this is our time slice beginning
		float fCurrStart = fStartInterval;

		//skip dead space on inactive effects
		if(!pFX->IsActive())
		{
			//sanity check, the shutting down flag should never be set without active
			assert(!pFX->IsShuttingDown());

			//This check is to verify that we aren't shutting down the instance and have inactive effects.
			//If we are shutting down, inactive effects are immediately pruned, and then active effects
			//should be removed as they are completed
			assert(!pInst->m_bShutdown);

			//figure out the start time of this effect
			float fKeyStart = pKey->m_tmStart;

			//this effect is not active. See if it should be (loop keys always should be)
			if(pKey->m_bContinualLoop || ((fKeyStart >= fCurrStart) && (fKeyStart <= fEndInterval)))
			{
				//our effect has just become active, we need to reset its elapsed time to 0,
				//and switch it over to an initial frame
				pFX->SetElapsed(0.0f);
				pFX->SetState(FS_ACTIVE | FS_INITIALFRAME);
				pFX->ClearState(FS_SHUTTINGDOWN);
				pFX->SetVisible(true);

				//handle applying a fake effect offset
				ApplyEffectStartingOffset(pFX, pKey);

				//move our timeslice forward to the beginning of the key
				fCurrStart = fKeyStart;
			}
		}

		if(pFX->IsActive())
		{
			//we are an active effect, which means we are either in the time block or are
			//shutting down. 

			//see if we are currently shutting down, and if we are going to transition into
			//becoming active
			if(pFX->IsShuttingDown())
			{
				float fKeyStart = pKey->m_tmStart;

				//however, we can only bring it into the active state from here if the instance
				//will allow us
				bool bCanActivate = pInst->m_bLoop && !pInst->m_bShutdown;

				//this effect is not active. See if it should be
				if(bCanActivate && (fKeyStart >= fCurrStart) && (fKeyStart <= fEndInterval))
				{
					//it will become active in this range, so move up to there and change state
					pFX->Update(fKeyStart - fCurrStart);

					pFX->SetElapsed(0.0f);
					pFX->SetState(FS_INITIALFRAME | FS_ACTIVE);
					pFX->ClearState(FS_SHUTTINGDOWN);

					//handle applying a fake effect offset
					ApplyEffectStartingOffset(pFX, pKey);

					//move our time position up to the key start
					fCurrStart = fKeyStart;
				}
			}

			//alright, we are now in a chunk of time where either the block is active
			//or shutting down. If it is active, we need to update until the end of the slice
			//or the end of the effect
			if(!pFX->IsShuttingDown())
			{
				//we aren't shutting down, so we can update like normal
				float fTimeBlockEnd = fEndInterval;
				bool bCompleteKey	= ((pKey->m_tmEnd <= fTimeBlockEnd) && (pKey->m_tmEnd >= fCurrStart));

				//see if we hit the end of the key
				if(bCompleteKey)
				{
					fTimeBlockEnd = pKey->m_tmEnd;
				}

				//update based upon the interval length
				pFX->Update(fTimeBlockEnd - fCurrStart);

				//the initial update state should be cleared now
				pFX->ClearState(FS_INITIALFRAME);

				//see if we completed the key
				if(bCompleteKey)
				{
					//we did, so now switch to a shutting down state if it isn't continually looping,
					//otherwise we need to reset the elapsed time to 0
					if(pKey->m_bContinualLoop && bLoopInstance)
					{
						//we have looped our key, so reset the elapsed amount. However, if we are a
						//continually looping effect that started with an offset, we don't want
						//to lose that offset and should threfore just wrap based upon the lifespan
						if(pKey->m_fMaxStartOffset >= 0.001f)
						{
							pFX->SetElapsed((float)fmod(pFX->GetElapsed(), pFX->GetLifespan()));
						}
						else
						{
							//no starting offset, so just to make sure that everything syncs
							//up correctly and no error gets introduced, reset it to 0
							pFX->SetElapsed(0.0f);
						}
					}
					else
					{
						//we're past our key, so start shutting down
						pFX->SetState(FS_SHUTTINGDOWN);
					}
				}

				//update our time start
				fCurrStart = fTimeBlockEnd;
			}

			//alright, now handle shutting down, in which case we just want to update however
			//much time we have left in this interval, and see if the effect is completed
			if(pFX->IsShuttingDown())
			{
				//allow it to update
				pFX->Update(fEndInterval - fCurrStart);

				//can this effect do a smooth shutdown?
				bool bSmoothShutdown = pKey->m_bSmoothShutdown && pInst->m_bSmoothShutdown;

				//see if this effect is done shutting down
				if(pFX->IsFinishedShuttingDown() || !bSmoothShutdown)
				{
					//notify of an effect that has finished shutting down
					HandleShutdownEffect(pInst, pActiveNode);

					//move onto the next node and keep processing
					pActiveNode = pNextActiveNode;
					continue;
				}
			}
		}
		
		//and onto the next node
		pActiveNode = pNextActiveNode;
	}
}