Sound parts are a new type of parts which you can use to directly add sounds via keyframes INTO the SFX! This is pretty helpful to reach a perfect "mixing" and timing of multiple(or single) sounds inside inside a SFX. If you are taking things serious and if you are working on good quality SFX, you'll need proper sounds! And those sounds can be used to give the perfect feeling in your game.

Open your ..\_Common\sfxbase.h

Take a look at the following enum:

enum SFXPARTTYPE {
	SFXPARTTYPE_BILL = 1,
	SFXPARTTYPE_PARTICLE = 2,
	SFXPARTTYPE_MESH = 3,
	SFXPARTTYPE_CUSTOMMESH = 4
};

REPLACE it with this:

enum SFXPARTTYPE {
	SFXPARTTYPE_BILL = 1,
	SFXPARTTYPE_PARTICLE = 2,
	SFXPARTTYPE_MESH = 3,
	SFXPARTTYPE_CUSTOMMESH = 4,
#ifdef __LNB_SFX_PART_SOUNDS
	SFXPARTTYPE_SOUND = 5,  // Add this new type for sound parts
#endif //__LNB_SFX_PART_SOUNDS
};

Now look for the following:

class CSfxBase

Add the following ABOVE it:

#ifdef __LNB_SFX_PART_SOUNDS
class CSfxPartSound: public CSfxPart {
public:
	CSfxPartSound();
	~CSfxPartSound() {
	}

	// Override base class methods(actually not too sure if we need to overwrite them all, but just in case..)
	virtual void Load(CResFile& file);
	virtual void Load2(CResFile& file);
	virtual void Load3(CResFile& file) {
	};
	virtual void OldLoad(CResFile& file);

#ifndef __WORLDSERVER
	virtual void Render(D3DXVECTOR3 vPos, WORD nFrame, FLOAT fAngle, D3DXVECTOR3 vScale = D3DXVECTOR3(1.0f, 1.0f, 1.0f));
#endif
	virtual void Render2(D3DXVECTOR3 vPos, WORD nFrame, D3DXVECTOR3 fAngle, D3DXVECTOR3 vScale = D3DXVECTOR3(1.0f, 1.0f, 1.0f));

private:
	WORD m_lastPlayedFrame;
};
#endif //__LNB_SFX_PART_SOUNDS

Next, open your ..\_Common\sfxbase.cpp

Look for the following:

CSfxPart::CSfxPart() {

Ensure to add the following ABOVE it:

#ifdef __LNB_SFX_PART_SOUNDS
static std::map<std::string, DWORD> g_playingSounds;
static const DWORD SOUND_COOLDOWN_MS = 100; // Minimum time between sound replays(ms.)
#endif//__LNB_SFX_PART_SOUNDS

Now look for CSfxPart* CSfxBase::AddPart(SFXPARTTYPE nType) {

and scroll down until you see the following:

		case SFXPARTTYPE_CUSTOMMESH:
		{
			pSfxPart = new CSfxPartCustomMesh;
			break;
		}

Place this UNDER it:

#ifdef __LNB_SFX_PART_SOUNDS
		case SFXPARTTYPE_SOUND:
		{
			pSfxPart = new CSfxPartSound;
			break;
		}
#endif //__LNB_SFX_PART_SOUNDS

Next, jump to BOOL CSfxModel::Render(LPDIRECT3DDEVICE9 pd3dDevice, const D3DXMATRIX* pmWorld) {

and look for this:

case SFXPARTTYPE_CUSTOMMESH:
{
    CSfxMng::m_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
    CSfxMng::m_pd3dDevice->SetFVF(D3DFVF_D3DSFXVERTEX);
    pPart->Render(m_vPos, m_nCurFrame, m_vRotate.y, m_vScale);
    CSfxMng::m_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
}
break;

Place this UNDER it:

#ifdef __LNB_SFX_PART_SOUNDS
case SFXPARTTYPE_SOUND:
{
CSfxPartSound* pSoundPart = static_cast<CSfxPartSound*>(pPart);
	if(pSoundPart)
	{
		pSoundPart->Render(m_vPos, m_nCurFrame, m_vRotate.y, m_vScale);
	}
	else
	{
		//You can remove this but for debugging purposes, you should keep this for your first try after implementing sound parts
		g_WndMng.PutString("Failed to cast to CSfxPartSound :c");
	}
}
break;
#endif //__LNB_SFX_PART_SOUNDS

Now scroll down to the very end of the sfxbase.cpp!

Then add this:

#ifdef __LNB_SFX_PART_SOUNDS
//Followed the same pattern of the already existing official weird SFX stuff...
CSfxPartSound::CSfxPartSound() {
	m_nType = SFXPARTTYPE_SOUND;
	m_lastPlayedFrame = 0xFFFF;
}

void CSfxPartSound::Load(CResFile& file) {
	int i;
	char strTemp[255];
	int nStrLen;

	file.Read(&nStrLen, sizeof(int));
	file.Read(strTemp, nStrLen); strTemp[nStrLen] = 0;
	m_strName = strTemp;
	m_strTex = strTemp; 
	
	//Not needed but lets keep those for compability ensurance
	m_nTexFrame = 1; 
	m_nTexLoop = 1;
	m_bUseing = TRUE;
	file.Read(&m_nBillType, sizeof(SFXPARTBILLTYPE));
	file.Read(&m_nAlphaType, sizeof(SFXPARTALPHATYPE));

	int nKey;
	file.Read(&nKey, sizeof(int));
	
	for(i = 0; i < nKey; i++) {
		WORD nFrame;
		file.Read(&nFrame, sizeof(WORD));
		
		AddKeyFrame(nFrame);
		SfxKeyFrame Key;
		file.Read(&(Key.vPos), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vPosRotate), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vScale), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vRotate), sizeof(D3DXVECTOR3));
		file.Read(&(Key.nAlpha), sizeof(int));
		AdjustKeyFrame(nFrame, Key);
	}
}

void CSfxPartSound::Load2(CResFile& file) {

	int i;
	char strTemp[255];
	int nStrLen;

	file.Read(&nStrLen, sizeof(int));
	file.Read(strTemp, nStrLen); strTemp[nStrLen] = 0;
	m_strName = strTemp;

	file.Read(&nStrLen, sizeof(int));
	file.Read(strTemp, nStrLen); strTemp[nStrLen] = 0;
	m_strTex = strTemp; 

	//Not needed but lets keep those for compability ensurance
	file.Read(&m_nTexFrame, sizeof(WORD));
	file.Read(&m_nTexLoop, sizeof(WORD));
	file.Read(&m_bUseing, sizeof(BOOL));
	file.Read(&m_nBillType, sizeof(SFXPARTBILLTYPE));
	file.Read(&m_nAlphaType, sizeof(SFXPARTALPHATYPE));

	int nKey;
	file.Read(&nKey, sizeof(int));
	
	for(i = 0; i < nKey; i++) {
		WORD nFrame;
		file.Read(&nFrame, sizeof(WORD));

		AddKeyFrame(nFrame);
		SfxKeyFrame Key;
		file.Read(&(Key.vPos), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vPosRotate), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vScale), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vRotate), sizeof(D3DXVECTOR3));
		file.Read(&(Key.nAlpha), sizeof(int));
		AdjustKeyFrame(nFrame, Key);
	}
}
void CSfxPartSound::OldLoad(CResFile& file) {
	int i;
	char strTemp[255];
	int nStrLen;

	file.Read(&nStrLen, sizeof(int));
	file.Read(strTemp, nStrLen); strTemp[nStrLen] = 0;
	m_strName = strTemp;
	m_strTex = strTemp; 

	//Not needed but lets keep those for compability ensurance
	m_nTexFrame = 1;
	m_nTexLoop = 1;
	m_bUseing = TRUE;
	file.Read(&m_nBillType, sizeof(SFXPARTBILLTYPE));
	file.Read(&m_nAlphaType, sizeof(SFXPARTALPHATYPE));

	int nKey;
	file.Read(&nKey, sizeof(int));
	
	for(i = 0; i < nKey; i++) {
		WORD nFrame;
		file.Read(&nFrame, sizeof(WORD));
		
		AddKeyFrame(nFrame);
		SfxKeyFrame Key;
		file.Read(&(Key.vPos), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vScale), sizeof(D3DXVECTOR3));
		file.Read(&(Key.vRotate), sizeof(D3DXVECTOR3));
		file.Read(&(Key.nAlpha), sizeof(int));

		Key.vPosRotate = D3DXVECTOR3(0, 0, 0);

		AdjustKeyFrame(nFrame, Key);
	}
}
#ifndef __WORLDSERVER
void CSfxPartSound::Render(D3DXVECTOR3 vPos, WORD nFrame, FLOAT fAngle, D3DXVECTOR3 vScale) {

	// If not set to "visible" inside the SFX itself, we dont play the sound
	if(!m_bUseing)
		return;
		
	if(m_lastPlayedFrame == nFrame)
		return;

	CString dbgStr;
	//For debugging. Keep it for possible later purposes, or just delete it
	//dbgStr.Format("Total keyframes: %d, Current frame: %d", m_apKeyFrames.GetSize(), nFrame);
	//g_WndMng.PutString(dbgStr);

	for(int i = 0; i < m_apKeyFrames.GetSize(); i++) {
		SfxKeyFrame* key = (SfxKeyFrame*)m_apKeyFrames[i];
		if(key && key->nFrame == nFrame) {
			if(!m_strTex.empty()) {
				DWORD currentTime = GetTickCount();
				std::string soundName = m_strTex.c_str();
				// Check if this sound is already playing and within cooldown period(100 ms. that we set before, feel free to change..)
				if(g_playingSounds.find(soundName) != g_playingSounds.end()) {
					DWORD lastPlayedTime = g_playingSounds[soundName];
					if(currentTime - lastPlayedTime < SOUND_COOLDOWN_MS) {
						// Sound is still in cooldown, dont play it again to prevent distortion
						return;
					}
				}

				// We wanna limit the size of the map to prevent memory leaks
				// Maybe not the best way but it works
				if(g_playingSounds.size() > 100) {
					// Clear thoes old entries
					g_playingSounds.clear();
				}
				
				// FInally play the sound
				PLAYSND(soundName.c_str(), &vPos);

				g_playingSounds[soundName] = currentTime;

				m_lastPlayedFrame = nFrame;
			}
			break;
		}
	}
}
#endif

void CSfxPartSound::Render2(D3DXVECTOR3 vPos, WORD nFrame, D3DXVECTOR3 fAngle, D3DXVECTOR3 vScale) {
#ifndef __WORLDSERVER
	Render(vPos, nFrame, fAngle.y, vScale);
#endif
}
#endif //__LNB_SFX_PART_SOUNDS

Do no forget to add the following to your versioncommon/servercommon:

#define		__LNB_SFX_PART_SOUNDS	//Newly implemented custom parts which support playing sound keyframes made in AToolsX!		

That's it! Your Neuz should now properly play sound parts and their content!

Make sure to compile your Neuz and try it - enjoy!

Last updated