// DS4QB++ slave - main moduole

#define WIN32_LEAN_AND_MEAN // (No MFC)

// Includes.

#include <windows.h>
#include <windowsx.h>
#include <winbase.h>
#include <mmsystem.h>
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <fcntl.h>
#include <windef.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "bass.h"
#include "ds4qb++.h"

void SendConfirm()
{
	if(Current_OS == WINNT)
	{
		if(_access(RECEIVECONFIRM, 0) == 0)
			while(remove(RECEIVECONFIRM)); Sleep(2);
	} else {
		_outp(0, 0); _outp(0, 0);
	}
}

int Buff2Long(int pos)
{
	return (int)(in_buffer[pos] + (in_buffer[pos + 1] << 8) + (in_buffer[pos + 2] << 16) + (in_buffer[pos + 3] << 32));
}

float Buff2Float(int pos)
{
	float Temp = 0;

	memcpy(&Temp, &in_buffer[pos], 4);

	return Temp;
}

void Long2Buff(int pos, int val)
{
	out_buffer[pos    ] = LOWORD(val) & 255;
	out_buffer[pos + 1] = LOWORD(val) >> 8;
	out_buffer[pos + 2] = HIWORD(val) & 255;
	out_buffer[pos + 3] = HIWORD(val) >> 8;
}

int Buff2Int(int pos)
{
	return (int)(in_buffer[pos] + (in_buffer[pos + 1] << 8));
}

void Int2Buff(int pos, int val)
{
	out_buffer[pos    ] = val & 255;
	out_buffer[pos + 1] = val >> 8;
}

BASS_3DVECTOR Buff2V3D(int pos)
{
	BASS_3DVECTOR Temp;

	Temp.x = Buff2Float(pos    );
	Temp.y = Buff2Float(pos + 4);
	Temp.z = Buff2Float(pos + 8);

	return Temp;
}

int FindAngle(int x1, int y1, int x2, int y2)
{
	int	  vx = x2 - x1,
		  vy = y2 - y1;
	float angle;

	if(vx > 0)
		angle = atan(vy / vx);
	else if(vx < 0)
		angle = atan(vy / vx) + pi;
	else if(vx = 0 && vy > 0)
		angle = pi * .5;
	else if(vx = 0 && vy < 0)
		angle = pi * 1.5;

	return(angle * (180 / pi));
	
}

int DMain(void)
{
	ScanInput();

	int Temp1, Temp2;
	char *bff;

	switch ( Buff2Int(0) )
	{
	case CMD_CLOSE:
		return(1);
		break;

	case CMD_PLAYSND:
		Sounds[Buff2Int(2)].Play(Buff2Long(4), Buff2Int(8), Buff2Int(10), Buff2Int(12));
		break;

	case CMD_LOADSND:
		Sounds[Buff2Int(2)].Load((char *)&in_buffer[4], Buff2Long(68));
		break;

	case CMD_STOPSND:
		Sounds[Buff2Int(2)].Stop();
		break;

	case CMD_SETSNDATTR:
		Sounds[Buff2Int(2)].SetInfo(Buff2Long(4), Buff2Int(8), Buff2Int(10), Buff2Int(12), (DWORD)Buff2Int(14));
		break;

	case CMD_DELETESND:
		Sounds[Buff2Int(2)].Delete();
		break;

	case CMD_LOADMUSIC:
		Musics[Buff2Int(2)].Load((char *)&in_buffer[4], Buff2Long(68), Buff2Int(72));
		break;

	case CMD_PLAYMUSIC:
		Musics[Buff2Int(2)].Play();
		break;

	case CMD_SETMUSICATTR:
		if(Buff2Int(2) == CDMUSIC)
				BASS_ChannelSetAttributes(CDCHANNEL, -1, Buff2Int(6), -1);
			else
				Musics[Buff2Int(2)].SetInfo(Buff2Int(4), Buff2Int(6));
		break;

	case CMD_PAUSEMUSIC:
		if(Buff2Int(2) == CDMUSIC)
				BASS_ChannelPause(CDCHANNEL);
			else
				Musics[Buff2Int(2)].Pause();
		break;

	case CMD_RESUMEMUSIC:
		if(Buff2Int(2) == CDMUSIC)
				BASS_ChannelResume(CDCHANNEL);
			else
				Musics[Buff2Int(2)].Resume();
		break;

	case CMD_STOPMUSIC:
		if(Buff2Int(2) == CDMUSIC)
				BASS_ChannelStop(CDCHANNEL);
			else
				Musics[Buff2Int(2)].Stop();
		break;

	case CMD_DELETEMUSIC:
		Musics[Buff2Int(2)].Delete();
		break;

	case CMD_SETVOLUME:
		Temp1 = Buff2Int(2);
		if(Temp1 == DEFAULT) Temp1 = -1;
		BASS_SetVolume((DWORD)Temp1);
		break;

	case CMD_SETGLOBALVOLS:
		Temp1 = Buff2Int(2); Temp2 = Buff2Int(4);
		if(Temp1 == DEFAULT) Temp1 = -1;
		if(Temp2 == DEFAULT) Temp2 = -1;
		BASS_SetGlobalVolumes((DWORD)Temp1, (DWORD)Temp2, -1);
		break;

	case CMD_GETMUSICLENGTH:
		Long2Buff(64, Musics[Buff2Int(2)].Length);
		SendOutput();
		break;

	case CMD_GETMUSICPOS:
		if(Buff2Int(2) == CDMUSIC)
				Long2Buff(64, BASS_ChannelGetPosition(CDCHANNEL) / 1000);	
			else
				Long2Buff(64, Musics[Buff2Int(2)].GetPos());
				
		SendOutput();
		break;

	case CMD_SETMUSICPOS:
		if(Buff2Int(2) == CDMUSIC)
				BASS_ChannelSetPosition(CDCHANNEL, Buff2Long(4) * 1000);
			else
				Musics[Buff2Int(2)].SetPos(Buff2Long(4));
		break;

	case CMD_SET2DPOS:

		memcpy(&TempSnd, &in_buffer[2], 6);
		if(TempSnd.Angle != DEFAULT) ear2d.Angle = TempSnd.Angle;
		if(TempSnd.x != DEFAULT) ear2d.Angle = TempSnd.x;
		if(TempSnd.y != DEFAULT) ear2d.Angle = TempSnd.y;
		break;

	case CMD_SET3DPOS:

		memcpy(&TempV[0], &in_buffer[2], 48);
		
		for(Temp1 = 0; Temp1 < 4; Temp1++)
			if(TempV[Temp1].x == (float)0xFFFFFF)
					pTempV[Temp1] = NULL;
				else
					pTempV[Temp1] = &TempV[Temp1];

		BASS_Set3DPosition(pTempV[0], pTempV[1], pTempV[2], pTempV[3]);
		BASS_Apply3D();
		break;

	case CMD_PLAYSND3D:
		
		memcpy(&TempV[0], &in_buffer[12], 36);
		
		Sounds[Buff2Int(2)].Play3D(Buff2Long(4), Buff2Int(8), Buff2Int(10), TempV[0], TempV[1], TempV[2]);
		
		break;
		
	case CMD_PLAYSND2D:
		
		memcpy(&TempSnd, &in_buffer[10], 6);
		
		Sounds[Buff2Int(2)].Play2D(Buff2Long(4), Buff2Int(8), TempSnd, ear2d);
		
		break;
		
	case CMD_SET3DFACTS:

		memcpy(&TempV[0], &in_buffer[2], 12);

		BASS_Set3DFactors(TempV[0].x, TempV[0].y, TempV[0].z);
		BASS_Apply3D();
		break;

	case CMD_PLAYSOUNDS:

		for(Temp1 = 1; Temp1 <= Buff2Int(2); Temp1++)
		{
			Temp2 = -10 + Temp1 * 14;
			Sounds[Buff2Int(Temp2 + 2)].Play(Buff2Long(Temp2 + 4), Buff2Int(Temp2 + 8), Buff2Int(Temp2 + 10), Buff2Int(Temp2 + 12));
		}

		break;

	case CMD_PLAY2DSOUNDS:

		memcpy(&TempSnd, &in_buffer[2], 6);
		if(TempSnd.Angle != DEFAULT) ear2d.Angle = TempSnd.Angle;
		if(TempSnd.x != DEFAULT) ear2d.x = TempSnd.x;
		if(TempSnd.y != DEFAULT) ear2d.y = TempSnd.y;
		
		for(Temp1 = 1; Temp1 <= Buff2Int(8); Temp1++)
		{
			Temp2 = -6 + Temp1 * 16;
			memcpy(&TempSnd, &in_buffer[Temp2 + 10], 6);
			Sounds[Buff2Int(Temp2 + 2)].Play2D(Buff2Long(Temp2 + 4), Buff2Int(Temp2 + 8), TempSnd, ear2d);
		}

		break;

	case CMD_PLAY3DSOUNDS:

		memcpy(&TempV[0], &in_buffer[2], 48);
		
		for(Temp1 = 0; Temp1 < 4; Temp1++)
			if(TempV[Temp1].x == (float)0xFFFFFF)
					pTempV[Temp1] = NULL;
				else
					pTempV[Temp1] = &TempV[Temp1];

		BASS_Set3DPosition(pTempV[0], pTempV[1], pTempV[2], pTempV[3]);
		BASS_Apply3D();

		for(Temp1 = 1; Temp1 <= Buff2Int(50); Temp1++)
		{
			Temp2 = 4 + Temp1 * 48;
			memcpy(&TempV[0], &in_buffer[Temp2 + 12], 36);
			Sounds[Buff2Int(Temp2 + 2)].Play3D(Buff2Long(Temp2 + 4), Buff2Int(Temp2 + 8), Buff2Int(Temp2 + 10), TempV[0], TempV[1], TempV[2]);
		}

		break;

	case CMD_SET2DDISTFACTOR:

		memcpy(&distf2d, &in_buffer[2], 4);

		break;

	case CMD_CDINIT:

		BASS_CDInit(NULL);

		break;

	case CMD_CDFREE:

		BASS_CDFree();

		break;

	case CMD_CDPLAY:

		BASS_CDPlay((DWORD)Buff2Int(2), (bool)Buff2Int(4), FALSE);

		break;

	case CMD_GETTRACKS:

		Int2Buff(64, BASS_CDGetTracks());
		SendOutput();

		break;

	case CMD_GETTRACKLENGTH:

		Long2Buff(64, BASS_CDGetTrackLength(Buff2Int(2)) / 1000);
		SendOutput();

		break;

	case CMD_SETEAX:

		memcpy(&TempV[0], &in_buffer[4], 12);

		Temp1 = Buff2Int(2);
		if(Temp1 == DEFAULT) Temp1 = -1;

		if(Temp1 < 27)
				BASS_SetEAXParameters(Temp1, TempV[0].x, TempV[0].y, TempV[0].z);
			else
			{
				switch (Temp1 - 27)
				{
				case EAX_ENVIRONMENT_GENERIC:
					BASS_SetEAXParameters(EAX_PRESET_GENERIC); break;

				case EAX_ENVIRONMENT_PADDEDCELL:
					BASS_SetEAXParameters(EAX_PRESET_PADDEDCELL); break;

				case EAX_ENVIRONMENT_ROOM:
					BASS_SetEAXParameters(EAX_PRESET_ROOM); break;

				case EAX_ENVIRONMENT_BATHROOM:
					BASS_SetEAXParameters(EAX_PRESET_BATHROOM); break;

				case EAX_ENVIRONMENT_LIVINGROOM:
					BASS_SetEAXParameters(EAX_PRESET_LIVINGROOM); break;

				case EAX_ENVIRONMENT_STONEROOM:
					BASS_SetEAXParameters(EAX_PRESET_STONEROOM); break;

				case EAX_ENVIRONMENT_AUDITORIUM:
					BASS_SetEAXParameters(EAX_PRESET_AUDITORIUM); break;

				case EAX_ENVIRONMENT_CONCERTHALL:
					BASS_SetEAXParameters(EAX_PRESET_CONCERTHALL); break;

				case EAX_ENVIRONMENT_CAVE:
					BASS_SetEAXParameters(EAX_PRESET_CAVE); break;

				case EAX_ENVIRONMENT_ARENA:
					BASS_SetEAXParameters(EAX_PRESET_ARENA); break;

				case EAX_ENVIRONMENT_HANGAR:
					BASS_SetEAXParameters(EAX_PRESET_HANGAR); break;

				case EAX_ENVIRONMENT_CARPETEDHALLWAY:
					BASS_SetEAXParameters(EAX_PRESET_CARPETEDHALLWAY); break;

				case EAX_ENVIRONMENT_HALLWAY:
					BASS_SetEAXParameters(EAX_PRESET_HALLWAY); break;

				case EAX_ENVIRONMENT_STONECORRIDOR:
					BASS_SetEAXParameters(EAX_PRESET_STONECORRIDOR); break;

				case EAX_ENVIRONMENT_ALLEY:
					BASS_SetEAXParameters(EAX_PRESET_ALLEY); break;

				case EAX_ENVIRONMENT_FOREST:
					BASS_SetEAXParameters(EAX_PRESET_FOREST); break;

				case EAX_ENVIRONMENT_CITY:
					BASS_SetEAXParameters(EAX_PRESET_CITY); break;

				case EAX_ENVIRONMENT_MOUNTAINS:
					BASS_SetEAXParameters(EAX_PRESET_MOUNTAINS); break;

				case EAX_ENVIRONMENT_QUARRY:
					BASS_SetEAXParameters(EAX_PRESET_QUARRY); break;

				case EAX_ENVIRONMENT_PLAIN:
					BASS_SetEAXParameters(EAX_PRESET_PLAIN); break;

				case EAX_ENVIRONMENT_PARKINGLOT:
					BASS_SetEAXParameters(EAX_PRESET_PARKINGLOT); break;

				case EAX_ENVIRONMENT_SEWERPIPE:
					BASS_SetEAXParameters(EAX_PRESET_SEWERPIPE); break;

				case EAX_ENVIRONMENT_UNDERWATER:
					BASS_SetEAXParameters(EAX_PRESET_UNDERWATER); break;

				case EAX_ENVIRONMENT_DRUGGED:
					BASS_SetEAXParameters(EAX_PRESET_DRUGGED); break;

				case EAX_ENVIRONMENT_DIZZY:
					BASS_SetEAXParameters(EAX_PRESET_DIZZY); break;

				case EAX_ENVIRONMENT_PSYCHOTIC:
					BASS_SetEAXParameters(EAX_PRESET_PSYCHOTIC); break;

				default:
					break;
				}
			}

		break;

	default:
		break;
	}
	
	SendConfirm();

	return(0);
}

int ScanInput(void)
{
	if(Current_OS == WINNT)
		while(_access(RECEIVECONFIRM, 0)) Sleep(5);
	else
		while(_inp(0) == 0) Sleep(2);

	// Open file, read data, close file.
	handle = fopen(INFILE, "rb+");
	fread(in_buffer, 1, 1024, handle);
	fclose(handle);

	return(0);
}

void SendOutput(void)
{
	handle = fopen(OUTFILE, "wb+");
	fwrite(out_buffer, sizeof(UCHAR), 128, handle);
	fclose(handle);
}

int Init(void)
{
	ScanInput();

	if(Buff2Int(0) != CMD_INITIALIZE) return(-1);

	if(!BASS_Init(-1 , (DWORD)Buff2Long(2), (DWORD)Buff2Long(6), NULL)) return(-2);
	
	BASS_Start();

	ear2d.x = 0; ear2d.y = 0; ear2d.Angle = 0;

	if(Buff2Long(6) & BASS_DEVICE_3D)
	{
		BASS_Set3DFactors(1.0, 1.0, 1.0);
		No3d = false;
	} else {
		No3d = true;
	}

	pi = atan(1) + atan(2) + atan(3);
	
	for(int i = 0; i <= 360; i++)
	{
		cosine[i] = cos(i * pi / 180.0);
		sine[i] = sin(i * pi / 180.0);
	}

	SendConfirm();

	return(0);
}

void DeInit(void)
{
	int i;

	for(i=1; i < 513; i++)
	{
		Sounds[i].Delete();
		Musics[i].Delete();
	}
	for(i=i; i < 1025; i++)
		Sounds[i].Delete();

	BASS_CDFree();
	BASS_Stop();
	BASS_Free();
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	return (DefWindowProc(hwnd, msg, wparam, lparam));
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)
{
	_setmode(_fileno(stdin), _O_BINARY);
	_setmode(_fileno(stdout), _O_BINARY);

	if((handle = fopen("..\\SOUNDSYS.CFG", "r")) != NULL)
	{
		fread(in_buffer, 1, 2, handle);
		fclose(handle);
		Current_OS = Buff2Int(0);
	}
	
	if(Init()) return(0);

	while(!DMain());
	
	DeInit();

	SendConfirm();

	return(1); // Succsess (0 = falure)
}