//-------------------------------------------------------------------------
/*
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 "mmulti.h"
#include "common_game.h"
#include "levels.h"
#include "map2d.h"
#include "trig.h"
#include "view.h"

BEGIN_BLD_NS

void sub_2541C(int x, int y, int z, short a)
{
    int tmpydim = (xdim * 5) / 8;
    renderSetAspect(65536, divscale16(tmpydim * 320, xdim * 200));
    int nCos = z*sintable[(0-a)&2047];
    int nSin = z*sintable[(1536-a)&2047];
    int nCos2 = mulscale16(nCos, yxaspect);
    int nSin2 = mulscale16(nSin, yxaspect);
    for (int i = 0; i < numsectors; i++)
    {
        if (gFullMap || (show2dsector[i>>3]&(1<<(i&7))))
        {
            int nStartWall = sector[i].wallptr;
            int nEndWall = nStartWall+sector[i].wallnum;
            int nZCeil = sector[i].ceilingz;
            int nZFloor = sector[i].floorz;
            walltype *pWall = &wall[nStartWall];
            for (int j = nStartWall; j < nEndWall; j++, pWall++)
            {
                int nNextWall = pWall->nextwall;
                if (nNextWall < 0)
                    continue;
                if (sector[pWall->nextsector].ceilingz == nZCeil && sector[pWall->nextsector].floorz == nZFloor
                    && ((wall[nNextWall].cstat | pWall->cstat) & 0x30) == 0)
                    continue;
                if (gFullMap)
                    continue;
                if (show2dsector[pWall->nextsector>>3]&(1<<(pWall->nextsector&7)))
                    continue;
                int wx = pWall->x-x;
                int wy = pWall->y-y;
                int cx = xdim<<11;
                int x1 = cx+dmulscale16(wx, nCos, -wy, nSin);
                int cy = ydim<<11;
                int y1 = cy+dmulscale16(wy, nCos2, wx, nSin2);
                walltype *pWall2 = &wall[pWall->point2];
                wx = pWall2->x-x;
                wy = pWall2->y-y;
                int x2 = cx+dmulscale16(wx, nCos, -wy, nSin);
                int y2 = cy+dmulscale16(wy, nCos2, wx, nSin2);
                renderDrawLine(x1,y1,x2,y2,24);
            }
        }
    }
    int nPSprite = gView->pSprite->index;
    for (int i = 0; i < numsectors; i++)
    {
        if (gFullMap || (show2dsector[i>>3]&(1<<(i&7))))
        {
            for (int nSprite = headspritesect[i]; nSprite >= 0; nSprite = nextspritesect[nSprite])
            {
                spritetype *pSprite = &sprite[nSprite];
                if (nSprite == nPSprite)
                    continue;
                if (pSprite->cstat&32768)
                    continue;
            }
        }
    }
    for (int i = 0; i < numsectors; i++)
    {
        if (gFullMap || (show2dsector[i>>3]&(1<<(i&7))))
        {
            int nStartWall = sector[i].wallptr;
            int nEndWall = nStartWall+sector[i].wallnum;
            walltype *pWall = &wall[nStartWall];
            int nNWall = -1;
            int x1, y1, x2 = 0, y2 = 0;
            for (int j = nStartWall; j < nEndWall; j++, pWall++)
            {
                int nNextWall = pWall->nextwall;
                if (nNextWall >= 0)
                    continue;
                if (!tilesiz[pWall->picnum].x || !tilesiz[pWall->picnum].y)
                    continue;
                if (nNWall == j)
                {
                    x1 = x2;
                    y1 = y2;
                }
                else
                {
                    int wx = pWall->x-x;
                    int wy = pWall->y-y;
                    x1 = (xdim<<11)+dmulscale16(wx, nCos, -wy, nSin);
                    y1 = (ydim<<11)+dmulscale16(wy, nCos2, wx, nSin2);
                }
                nNWall = pWall->point2;
                walltype *pWall2 = &wall[nNWall];
                int wx = pWall2->x-x;
                int wy = pWall2->y-y;
                x2 = (xdim<<11)+dmulscale16(wx, nCos, -wy, nSin);
                y2 = (ydim<<11)+dmulscale16(wy, nCos2, wx, nSin2);
                renderDrawLine(x1,y1,x2,y2,24);
            }
        }
    }
    videoSetCorrectedAspect();

    for (int i = connecthead; i >= 0; i = connectpoint2[i])
    {
        if (gViewMap.bFollowMode || gView->at57 != i)
        {
            PLAYER *pPlayer = &gPlayer[i];
            spritetype *pSprite = pPlayer->pSprite;
            int px = pSprite->x-x;
            int py = pSprite->y-y;
            int pa = (pSprite->ang-a)&2047;
            if (i == gView->at57)
            {
                px = 0;
                py = 0;
                pa = 0;
            }
            int x1 = dmulscale16(px, nCos, -py, nSin);
            int y1 = dmulscale16(py, nCos2, px, nSin2);
            if (i == gView->at57 || gGameOptions.nGameType == 1)
            {
                int nTile = pSprite->picnum;
                int ceilZ, ceilHit, floorZ, floorHit;
                GetZRange(pSprite, &ceilZ, &ceilHit, &floorZ, &floorHit, (pSprite->clipdist<<2)+16, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR);
                int nTop, nBottom;
                GetSpriteExtents(pSprite, &nTop, &nBottom);
                int nScale = mulscale((pSprite->yrepeat+((floorZ-nBottom)>>8))*z, yxaspect, 16);
                nScale = ClipRange(nScale, 8000, 65536<<1);
                rotatesprite((xdim<<15)+(x1<<4), (ydim<<15)+(y1<<4), nScale, pa, nTile, pSprite->shade, pSprite->pal, (pSprite->cstat&2)>>1,
                    windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y);
            }
        }
    }
}

CViewMap::CViewMap()
{
    bActive = 0;
}

void CViewMap::sub_25C38(int _x, int _y, int _angle, short zoom, char unk1)
{
    bActive = 1;
    x = _x;
    y = _y;
    angle = _angle;
    nZoom = zoom;
    FollowMode(unk1);
    forward = 0;
    turn = 0;
    strafe = 0;
}

void CViewMap::sub_25C74(void)
{
    char pBuffer[128];
    if (!bActive)
        return;
    char tm = 0;
    int viewSize = gViewSize;
    if (gViewSize > 3)
    {
        viewResizeView(3);
        tm = 1;
    }
    videoClearScreen(0);
    renderDrawMapView(x,y,nZoom>>2,angle);
    sub_2541C(x,y,nZoom>>2,angle);
    char *pTitle = levelGetTitle();
    char *pFilename = levelGetFilename(gGameOptions.nEpisode, gGameOptions.nLevel);
    if (pTitle)
        sprintf(pBuffer, "%s: %s", pFilename, pTitle);
    else
        sprintf(pBuffer, "%s", pFilename);
    int nViewY;
    if (gViewSize > 3)
        nViewY = gViewY1S-16;
    else
        nViewY = gViewY0S+1;
    viewDrawText(3, pBuffer, gViewX1S, nViewY, -128, 0, 2, 0, 256);

    if (gViewMap.bFollowMode)
        viewDrawText(3, "MAP FOLLOW MODE", gViewX1S, nViewY+8, -128, 0, 2, 0, 256);
    else
        viewDrawText(3, "MAP SCROLL MODE", gViewX1S, nViewY+8, -128, 0, 2, 0, 256);
    if (tm)
        viewResizeView(viewSize);
}

void CViewMap::sub_25DB0(spritetype *pSprite)
{
    nZoom = gZoom;
    if (bFollowMode)
    {
        x = pSprite->x;
        y = pSprite->y;
        angle = pSprite->ang;
    }
    else
    {
        angle += turn>>3;
        x += mulscale24(forward, Cos(angle));
        y += mulscale24(forward, Sin(angle));
        x -= mulscale24(strafe, Cos(angle+512));
        y -= mulscale24(strafe, Sin(angle+512));
        forward = 0;
        strafe = 0;
        turn = 0;
    }
    sub_25C74();
}

void CViewMap::sub_25E84(int *_x, int *_y)
{
    if (_x)
        *_x = x;
    if (_y)
        *_y = y;
}

void CViewMap::FollowMode(char mode)
{
    bFollowMode = mode;
}

CViewMap gViewMap;


END_BLD_NS
