
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.
ATTENTION:
There is no guarantee that those source changes work 100% on your server files and i will NOT provide any support on how to add those. You are responsible on your own to add the given code properly according to the guides posted!
Without the source changes of the corresponding Features, those Features will NOT work for you!
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