//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT

This file is part of NBlood.

NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
//-------------------------------------------------------------------------

#include "ns.h"	// Must come before everything else!

#include "build.h"
#include "fx_man.h"
#include "common_game.h"
//#include "blood.h"
#include "config.h"
#include "db.h"
#include "player.h"
#include "resource.h"
#include "sound.h"

BEGIN_BLD_NS

#define kMaxAmbChannel 64

struct AMB_CHANNEL
{
    int at0;
    int at4;
    int at8;
    DICTNODE *atc;
    char *at10;
    int at14;
    int at18;
};

AMB_CHANNEL ambChannels[kMaxAmbChannel];
int nAmbChannels = 0;

void ambProcess(void)
{
    if (!SoundToggle)
        return;
    for (int nSprite = headspritestat[12]; nSprite >= 0; nSprite = nextspritestat[nSprite])
    {
        spritetype *pSprite = &sprite[nSprite];
        if (pSprite->owner < 0 || pSprite->owner >= kMaxAmbChannel)
            continue;
        int nXSprite = pSprite->extra;
        if (nXSprite > 0 && nXSprite < kMaxXSprites)
        {
            XSPRITE *pXSprite = &xsprite[nXSprite];
            if (pXSprite->state)
            {
                int dx = pSprite->x-gMe->pSprite->x;
                int dy = pSprite->y-gMe->pSprite->y;
                int dz = pSprite->z-gMe->pSprite->z;
                dx >>= 4;
                dy >>= 4;
                dz >>= 8;
                int nDist = ksqrt(dx*dx+dy*dy+dz*dz);
                int vs = mulscale16(pXSprite->data4, pXSprite->busy);
                ambChannels[pSprite->owner].at4 += ClipRange(scale(nDist, pXSprite->data1, pXSprite->data2, vs, 0), 0, vs);
            }
        }
    }
    AMB_CHANNEL *pChannel = ambChannels;
    for (int i = 0; i < nAmbChannels; i++, pChannel++)
    {
        if (pChannel->at0 > 0)
            FX_SetPan(pChannel->at0, pChannel->at4, pChannel->at4, pChannel->at4);
        else
        {
            int end = ClipLow(pChannel->at14-1, 0);
            pChannel->at0 = FX_PlayLoopedRaw(pChannel->at10, pChannel->at14, pChannel->at10, pChannel->at10+end, sndGetRate(pChannel->at18), 0,
                pChannel->at4, pChannel->at4, pChannel->at4, pChannel->at4, 1.f, (intptr_t)&pChannel->at0);
        }
        pChannel->at4 = 0;
    }
}

void ambKillAll(void)
{
    AMB_CHANNEL *pChannel = ambChannels;
    for (int i = 0; i < nAmbChannels; i++, pChannel++)
    {
        if (pChannel->at0 > 0)
        {
            FX_EndLooping(pChannel->at0);
            FX_StopSound(pChannel->at0);
        }
        if (pChannel->atc)
        {
            gSoundRes.Unlock(pChannel->atc);
            pChannel->atc = NULL;
        }
    }
    nAmbChannels = 0;
}

void ambInit(void)
{
    ambKillAll();
    memset(ambChannels, 0, sizeof(ambChannels));
    for (int nSprite = headspritestat[12]; nSprite >= 0; nSprite = nextspritestat[nSprite])
    {
        spritetype *pSprite = &sprite[nSprite];
        int nXSprite = pSprite->extra;
        if (nXSprite > 0 && nXSprite < kMaxXSprites)
        {
            XSPRITE *pXSprite = &xsprite[nXSprite];
            if (pXSprite->data1 < pXSprite->data2)
            {
                int i;
                AMB_CHANNEL *pChannel = ambChannels;
                for (i = 0; i < nAmbChannels; i++, pChannel++)
                    if (pXSprite->data3 == pChannel->at8)
                        break;
                if (i == nAmbChannels)
                {
                    if (i >= kMaxAmbChannel)
                    {
                        pSprite->owner = -1;
                        continue;
                    }
                    int nSFX = pXSprite->data3;
                    DICTNODE *pSFXNode = gSoundRes.Lookup(nSFX, "SFX");
                    if (!pSFXNode)
                        ThrowError("Missing sound #%d used in ambient sound generator %d\n", nSFX);
                    SFX *pSFX = (SFX*)gSoundRes.Load(pSFXNode);
                    DICTNODE *pRAWNode = gSoundRes.Lookup(pSFX->rawName, "RAW");
                    if (!pRAWNode)
                        ThrowError("Missing RAW sound \"%s\" used in ambient sound generator %d\n", pSFX->rawName, nSFX);
                    if (pRAWNode->size > 0)
                    {
                        pChannel->at14 = pRAWNode->size;
                        pChannel->at8 = nSFX;
                        pChannel->atc = pRAWNode;
                        pChannel->at14 = pRAWNode->size;
                        pChannel->at10 = (char*)gSoundRes.Lock(pRAWNode);
                        pChannel->at18 = pSFX->format;
                        nAmbChannels++;
                    }
                }
                pSprite->owner = i;
            }
        }
    }
}

END_BLD_NS
