By default, the Neuz does not properly handle "Unlimited Loop"-type SFX parts from particles.

It does affect ALL other parts of the SFX if enabled on any of the SFX parts. This leads to unwanted behavior.

Example without fix:

Example with fix:

To fix this, apply the code below.

Open your ..\_Common\sfxbase.cpp

Go into the following function: CSfxModel::Process(void)

Look for this:

if(pPartParticle->Key(0))
{
    nStartFrame = pPartParticle->Key(0)->nFrame;
    nEndFrame = pPartParticle->Key(pPartParticle->m_apKeyFrames.GetSize() - 1)->nFrame;
}

Place the following UNDER it:

#ifdef __LNB_FIX_SFX_REPEAT
if(pPartParticle->m_bRepeat && m_nCurFrame > nEndFrame)
{
    continue;
}
#endif //#ifdef __LNB_FIX_SFX_REPEAT

Scroll a bit down until you see the following:

if(m_nCurFrame >= nStartFrame && m_nCurFrame <= nEndFrame - pPartParticle->m_nParticleFrameDisappear) {

REPLACE it with:

#ifdef __LNB_FIX_SFX_REPEAT
			int nEffectiveFrame = m_nCurFrame;

			if(pPartParticle->m_bRepeat && nEndFrame > 0)
			{
				int lastSpawnFrame = nEndFrame - pPartParticle->m_nParticleFrameDisappear;

				if(m_nCurFrame >= lastSpawnFrame)
				{
					if(pPartParticle->m_nParticleCreate > 0)
					{
						int framesPast = m_nCurFrame - lastSpawnFrame;
						nEffectiveFrame = nStartFrame + (framesPast % pPartParticle->m_nParticleCreate);
					}
					else
					{
						nEffectiveFrame = nStartFrame;
					}
				}
			}

			if(nEffectiveFrame >= nStartFrame && nEffectiveFrame <= nEndFrame - pPartParticle->m_nParticleFrameDisappear) {
#else //#ifdef __LNB_FIX_SFX_REPEAT
			if(m_nCurFrame >= nStartFrame && m_nCurFrame <= nEndFrame - pPartParticle->m_nParticleFrameDisappear) {
#endif //#ifdef __LNB_FIX_SFX_REPEAT

Scroll a bit down until you see the following:

if(m_nCurFrame == nStartFrame)
{

REPLACE it with:

#ifdef __LNB_FIX_SFX_REPEAT
					if(nEffectiveFrame == nStartFrame)
					{
#else //#ifdef __LNB_FIX_SFX_REPEAT
					if(m_nCurFrame == nStartFrame)
					{
#endif //#ifdef __LNB_FIX_SFX_REPEAT

Again, scroll a bit down until you see the following:

if(((m_nCurFrame)-nStartFrame) % pPartParticle->m_nParticleCreate == 0) {

REPLACE it with:

#ifdef __LNB_FIX_SFX_REPEAT
					if(((nEffectiveFrame)-nStartFrame) % pPartParticle->m_nParticleCreate == 0) {
#else //#ifdef __LNB_FIX_SFX_REPEAT
					if(((m_nCurFrame)-nStartFrame) % pPartParticle->m_nParticleCreate == 0) {
#endif //#ifdef __LNB_FIX_SFX_REPEAT

Scroll down even more and you will see:

	if(pPartParticle->m_bRepeat)
	{
		if(nEndFrame >= 0)
		{
			FLOAT f = (FLOAT)m_nCurFrame / (FLOAT)nEndFrame;

			if(f >= 0.65f)
			{
				m_nCurFrame = (int)(nEndFrame * 0.6f);
			}
		}
		else
		{
			Error(" CSfxModel::Process()에서 nEndFrame < 0");
		}
	}

REPLACE it with:

#ifdef __LNB_FIX_SFX_REPEAT
if(!pPartParticle->m_bRepeat && m_nCurFrame > nEndFrame)
{
	continue;
}
#else //#ifdef __LNB_FIX_SFX_REPEAT
if(pPartParticle->m_bRepeat)
{
	if(nEndFrame >= 0)
	{
		FLOAT f = (FLOAT)m_nCurFrame / (FLOAT)nEndFrame;

		if(f >= 0.65f)
		{
			m_nCurFrame = (int)(nEndFrame * 0.6f);
		}
	}
	else
	{
		Error(" CSfxModel::Process()에서 nEndFrame < 0");
	}
}
#endif //#ifdef __LNB_FIX_SFX_REPEAT

Lastly, scroll more and find this:

return ret;

Place the following ABOVE it:

#ifdef __LNB_FIX_SFX_REPEAT
	if(!anyPartActive)
	{
		ret = TRUE;
	}
#endif //#ifdef __LNB_FIX_SFX_REPEAT

For clarification, this is my entire function:

BOOL CSfxModel::Process(void) {
	BOOL ret = TRUE;
	CSfxPartParticle* pPartParticle;
	Particle* pParticle;

	m_nCurFrame++;
	bool anyPartActive = false;

	// 이 sfx에 파티클 part가 포함되어 있다면 파티클의 생성, 파괴 등을 처리한다.
	for(int i = 0; i < m_apParticles.GetSize(); i++) {
		CPtrArray* pParticles = (CPtrArray*)m_apParticles[i];
		if(pParticles) {
			pPartParticle = (CSfxPartParticle*)(m_pSfxBase->Part(i));

			if(pPartParticle->m_bUseing == FALSE)
				continue;

			int nStartFrame = 0;
			int nEndFrame = 0;
			if(pPartParticle->Key(0)) {
				nStartFrame = pPartParticle->Key(0)->nFrame;
				nEndFrame = pPartParticle->Key(pPartParticle->m_apKeyFrames.GetSize() - 1)->nFrame;
			}

#ifdef __LNB_FIX_SFX_REPEAT
			if(pPartParticle->m_bRepeat && m_nCurFrame > nEndFrame) {
				continue;
			}
#endif //#ifdef __LNB_FIX_SFX_REPEAT

			// If we reach here, this part is still active
			anyPartActive = true;

			SfxKeyFrame Key;
			pPartParticle->GetKey(m_nCurFrame, &Key);

			// 파티클 이동, 생성 및 제거
			int j;
			for(j = 0; j < pParticles->GetSize(); j++) {
				pParticle = (Particle*)(pParticles->GetAt(j));
				pParticle->vPos += pParticle->vSpeed;
				pParticle->vSpeed += pPartParticle->m_vParticleAccel;

				if(!pPartParticle->m_bRepeatScal)
					pParticle->vScale += pPartParticle->m_vScaleSpeed;

				pParticle->nFrame++;

				if(pParticle->nFrame >= pPartParticle->m_nParticleFrameDisappear) {
					safe_delete(pParticle);
					pParticles->RemoveAt(j);
					j--;
				}
			}

#ifdef __LNB_FIX_SFX_REPEAT
			int nEffectiveFrame = m_nCurFrame;

			if(pPartParticle->m_bRepeat && nEndFrame > 0) {
				int lastSpawnFrame = nEndFrame - pPartParticle->m_nParticleFrameDisappear;

				if(m_nCurFrame >= lastSpawnFrame) {
					if(pPartParticle->m_nParticleCreate > 0) {
						int framesPast = m_nCurFrame - lastSpawnFrame;
						nEffectiveFrame = nStartFrame + (framesPast % pPartParticle->m_nParticleCreate);
				}
					else {
						nEffectiveFrame = nStartFrame;
					}
				}
					}

			if(nEffectiveFrame >= nStartFrame && nEffectiveFrame <= nEndFrame - pPartParticle->m_nParticleFrameDisappear) {
#else //#ifdef __LNB_FIX_SFX_REPEAT
			if(m_nCurFrame >= nStartFrame && m_nCurFrame <= nEndFrame - pPartParticle->m_nParticleFrameDisappear) {
#endif //#ifdef __LNB_FIX_SFX_REPEAT
				float fRand1 = RANDF;
				float fRand2 = RANDF;
				float fRand3 = RANDF;

				if(pPartParticle->m_nParticleCreate == 0) {
#ifdef __LNB_FIX_SFX_REPEAT
					if(nEffectiveFrame == nStartFrame) {
#else //#ifdef __LNB_FIX_SFX_REPEAT
					if(m_nCurFrame == nStartFrame) {
#endif //#ifdef __LNB_FIX_SFX_REPEAT
						for(int i = 0; i < pPartParticle->m_nParticleCreateNum; i++) {
							pParticle = new Particle;
							pParticle->nFrame = 0;
							float fAngle = RANDF * 360.0f;
							pParticle->vPos =
								D3DXVECTOR3(
									sin(fAngle) * pPartParticle->m_fParticleStartPosVar,
									fRand1 * pPartParticle->m_fParticleStartPosVarY,
									cos(fAngle) * pPartParticle->m_fParticleStartPosVar
								);
							float fFactor = pPartParticle->m_fParticleXZLow + fRand2 * (pPartParticle->m_fParticleXZHigh - pPartParticle->m_fParticleXZLow);
							pParticle->vSpeed =
								D3DXVECTOR3(
									sin(fAngle) * fFactor,
									pPartParticle->m_fParticleYLow + fRand2 * (pPartParticle->m_fParticleYHigh - pPartParticle->m_fParticleYLow),
									cos(fAngle) * fFactor
								);
							pParticle->vScaleStart = pParticle->vScale = pPartParticle->m_vScale;
							//#ifdef __ATEST
							pParticle->vRotation = D3DXVECTOR3(pPartParticle->m_vRotationLow.x + fRand1 *
															   (pPartParticle->m_vRotationHigh.x - pPartParticle->m_vRotationLow.x),
															   pPartParticle->m_vRotationLow.y + fRand3 *
															   (pPartParticle->m_vRotationHigh.y - pPartParticle->m_vRotationLow.y),
															   pPartParticle->m_vRotationLow.z + fRand2 *
															   (pPartParticle->m_vRotationHigh.z - pPartParticle->m_vRotationLow.z));


							pParticle->bSwScal = FALSE;
							pParticle->vScaleEnd = pPartParticle->m_vScaleEnd;
							pParticle->vScaleSpeed = D3DXVECTOR3(pPartParticle->m_fScalSpeedXLow + fRand3 *
																 (pPartParticle->m_fScalSpeedXHigh - pPartParticle->m_fScalSpeedXLow),
																 pPartParticle->m_fScalSpeedYLow + fRand2 *
																 (pPartParticle->m_fScalSpeedYHigh - pPartParticle->m_fScalSpeedYLow),
																 pPartParticle->m_fScalSpeedZLow + fRand1 *
																 (pPartParticle->m_fScalSpeedZHigh - pPartParticle->m_fScalSpeedZLow));


							//#endif
							pParticles->Add(pParticle);
						}
					}
					}
				else {
#ifdef __LNB_FIX_SFX_REPEAT
					if(((nEffectiveFrame)-nStartFrame) % pPartParticle->m_nParticleCreate == 0) {
#else //#ifdef __LNB_FIX_SFX_REPEAT
					if(((m_nCurFrame)-nStartFrame) % pPartParticle->m_nParticleCreate == 0) {
#endif //#ifdef __LNB_FIX_SFX_REPEAT
						for(int i = 0; i < pPartParticle->m_nParticleCreateNum; i++) {
							pParticle = new Particle;
							pParticle->nFrame = 0;
							float fAngle = RANDF * 360.0f;
							pParticle->vPos =
								D3DXVECTOR3(
									sin(fAngle) * pPartParticle->m_fParticleStartPosVar,
									fRand1 * pPartParticle->m_fParticleStartPosVarY,
									cos(fAngle) * pPartParticle->m_fParticleStartPosVar
								);
							float fFactor = pPartParticle->m_fParticleXZLow + fRand2 * (pPartParticle->m_fParticleXZHigh - pPartParticle->m_fParticleXZLow);
							pParticle->vSpeed =
								D3DXVECTOR3(
									sin(fAngle) * fFactor,
									pPartParticle->m_fParticleYLow + fRand2 * (pPartParticle->m_fParticleYHigh - pPartParticle->m_fParticleYLow),
									cos(fAngle) * fFactor
								);
							pParticle->vScaleStart = pParticle->vScale = pPartParticle->m_vScale;
							//#ifdef __ATEST
							pParticle->vRotation = D3DXVECTOR3(pPartParticle->m_vRotationLow.x + fRand1 *
															   (pPartParticle->m_vRotationHigh.x - pPartParticle->m_vRotationLow.x),
															   pPartParticle->m_vRotationLow.y + fRand3 *
															   (pPartParticle->m_vRotationHigh.y - pPartParticle->m_vRotationLow.y),
															   pPartParticle->m_vRotationLow.z + fRand2 *
															   (pPartParticle->m_vRotationHigh.z - pPartParticle->m_vRotationLow.z));


							pParticle->bSwScal = FALSE;
							pParticle->vScaleEnd = pPartParticle->m_vScaleEnd;
							pParticle->vScaleSpeed = D3DXVECTOR3(pPartParticle->m_fScalSpeedXLow + fRand3 *
																 (pPartParticle->m_fScalSpeedXHigh - pPartParticle->m_fScalSpeedXLow),
																 pPartParticle->m_fScalSpeedYLow + fRand2 *
																 (pPartParticle->m_fScalSpeedYHigh - pPartParticle->m_fScalSpeedYLow),
																 pPartParticle->m_fScalSpeedZLow + fRand1 *
																 (pPartParticle->m_fScalSpeedZHigh - pPartParticle->m_fScalSpeedZLow));


							//#endif
							pParticles->Add(pParticle);
						}
					}
					}
				}

			if(pParticles->GetSize() > 0)
				ret = FALSE;

			if(m_nCurFrame < nStartFrame)
				ret = FALSE;

#ifdef __LNB_FIX_SFX_REPEAT
			if(!pPartParticle->m_bRepeat && m_nCurFrame > nEndFrame) {
				continue;
					}
#else //#ifdef __LNB_FIX_SFX_REPEAT
			if(pPartParticle->m_bRepeat) {
				if(nEndFrame >= 0) {
					FLOAT f = (FLOAT)m_nCurFrame / (FLOAT)nEndFrame;

					if(f >= 0.65f) {
						m_nCurFrame = (int)(nEndFrame * 0.6f);
					}
				}
				else {
					Error(" CSfxModel::Process()에서 nEndFrame < 0");
				}
			}
#endif //#ifdef __LNB_FIX_SFX_REPEAT
				}
		else {
			if(m_pSfxBase->Part(i)->GetNextKey(m_nCurFrame)) {
				anyPartActive = true;
				ret = FALSE;
			}
		}
				}

#ifdef __LNB_FIX_SFX_REPEAT
	if(!anyPartActive) {
		ret = TRUE;
	}
#endif //#ifdef __LNB_FIX_SFX_REPEAT

#ifdef __HERTZ_OPT
	if(g_Option.m_bUnlockFps) {
		this->UpdateFrameTime();
	}
#endif
	return ret;
}

That's it! Your Neuz should now support animated "Unlimited Loop"-type SFX aka m_bRepeat!

Make sure to define __LNB_FIX_SFX_REPEAT in your servercommon.h/versioncommon.h(or wherever you define stuff), compile your Neuz and try it - enjoy!

Last updated