////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Sprites.cpp

#include "stdhdr.h"

#include "Draw.h"
#include "Logic.h"
#include "Sprites.h"

/////////////////////////////////////////////////////////////////////////////
// CSprite

CSprite::CSprite()
{
    m_x = m_y = m_vx = m_vy = 0;
    m_cx = m_cy = m_nFrame = m_xImage = m_yImage = 0;
    m_nFramesMax = m_nFramesAcross = 1;
    m_lpSurface = NULL;
    m_dwFlag = DDBLTFAST_SRCCOLORKEY;
}

CSprite::CSprite(IDirectDrawSurface7 *lpSurface, int xImage, int yImage, int cx, int cy, int nFramesMax, int nFramesAcross)
{
    m_x = m_y = m_vx = m_vy = 0;
    m_cx = cx;
    m_cy = cy;
    m_nFrame = 0;
    m_xImage = xImage;
    m_yImage = yImage;
    m_nFramesMax = nFramesMax;
    m_nFramesAcross = (nFramesAcross == -1) ? nFramesMax : nFramesAcross;
    m_lpSurface = lpSurface;
    m_dwFlag = DDBLTFAST_SRCCOLORKEY;
}

CSprite::CSprite(CSprite& s)
{
    m_x = s.m_x;
    m_y = s.m_y;
    m_vx = s.m_vx;
    m_vy = s.m_vy;
    m_cx = s.m_cx;
    m_cy = s.m_cy;
    m_nFrame = s.m_nFrame;
    m_xImage = s.m_xImage;
    m_yImage = s.m_yImage;
    m_nFramesMax = s.m_nFramesMax;
    m_nFramesAcross = s.m_nFramesAcross;
    m_lpSurface = s.m_lpSurface;
    m_dwFlag = s.m_dwFlag;
}

void CSprite::NextFrame(void)
{
    m_nFrame++;
    m_nFrame %= m_nFramesMax;
}

void CSprite::Move(void)
{
    m_x += FrameAbsVelocity(m_vx);
    m_y += FrameAbsVelocity(m_vy);
}

void CSprite::Draw()
{
    RECT    rcRect;

    rcRect.left = m_xImage + (m_cx * (m_nFrame % m_nFramesAcross));
    rcRect.top = m_yImage + ((m_nFrame / m_nFramesAcross) * m_cy);
    rcRect.right = rcRect.left + m_cx;
    rcRect.bottom = rcRect.top + m_cy;

    BackBlt((int)m_x, (int)m_y, m_lpSurface, &rcRect, m_dwFlag);
}

//////////////////////////////////////////////////////////////////////
// Player sprite

CPlayerSprite::CPlayerSprite(double nVelocity) : CSprite()
{
    m_nDirection = m_nNextDirection = STOPPED;
    m_cx = m_cy = BLOCKSIZE;
    m_lpSurface = lpImages;
    m_xImage = PLAYERX;
    m_yImage = PLAYERY;
    m_nFramesAcross = m_nFramesMax = PLAYERFRAMES;
    m_nVelocity = nVelocity;
    m_bAtGrid = TRUE;
}

CPlayerSprite::CPlayerSprite(CPlayerSprite& s) : CSprite(s)
{
    m_nDirection = s.m_nDirection;
    m_nNextDirection = s.m_nNextDirection;
    m_nVelocity = s.m_nVelocity;
    m_bAtGrid = s.m_bAtGrid;
}

void CPlayerSprite::Move()
{
    int nOldX = (int)m_x / BLOCKSIZE, nOldY = (int)m_y / BLOCKSIZE;
    double xOld = m_x, yOld = m_y;

    m_vx = m_vy = 0;
    switch (m_nDirection)
    {
    case STOPPED:
        break;

    case UP:
        m_vy = -m_nVelocity;
        break;

    case DOWN:
        m_vy = m_nVelocity;
        break;

    case LEFT:
        m_vx = -m_nVelocity;
        break;

    case RIGHT:
        m_vx = m_nVelocity;
        break;
    }
    
    CSprite::Move();

    // Clip the sprite against the corners of the screen
    if (m_x < 0)
        m_x = 0;
    if (m_x >= ((XBLOCKS - 1) * BLOCKSIZE))
        m_x = (XBLOCKS - 1) * BLOCKSIZE;
    if (m_y < 0)
        m_y = 0;
    if (m_y >= ((YBLOCKS - 1) * BLOCKSIZE))
        m_y = (YBLOCKS - 1) * BLOCKSIZE;

    int nX = (int)m_x / BLOCKSIZE;
    int nY = (int)m_y / BLOCKSIZE;

    if (nOldX > nX)
    {
        if (xOld > nOldX * BLOCKSIZE)
            m_x = nOldX * BLOCKSIZE;
    }   
    else if (nOldX < nX)
        m_x = floor(m_x / BLOCKSIZE) * BLOCKSIZE;

    if (nOldY > nY)
    {
        if (yOld > nOldY * BLOCKSIZE)
            m_y = nOldY * BLOCKSIZE;
    }   
    else if (nOldY < nY)
        m_y = floor(m_y / BLOCKSIZE) * BLOCKSIZE;

    // If the sprite has reached a grid position, start moving in the new direction.

    m_bAtGrid = ((((int)m_x % BLOCKSIZE) == 0) && (((int)m_y % BLOCKSIZE) == 0)) ? TRUE : FALSE;

    if (m_bAtGrid && (m_nDirection != m_nNextDirection))    
    {
        m_nDirection = m_nNextDirection;
        m_x = floor(m_x);
        m_y = floor(m_y);
    }
}

//////////////////////////////////////////////////////////////////////
// Enemy sprite

CEnemySprite::CEnemySprite()
{
    m_x = XBLOCKS / 2;
    m_y = YBLOCKS / 2;
    m_cx = m_cy = BLOCKSIZE;
    m_vx = m_vy = 2.5;
    m_lpSurface = lpImages;
    m_xImage = ENEMYX;
    m_yImage = ENEMYY;
    m_nFramesAcross = m_nFramesMax = ENEMYFRAMES;
}

CEnemySprite::CEnemySprite(CEnemySprite& s) : CSprite(s)
{
}

void CEnemySprite::Move()
{
    int nOldX = (int)m_x / BLOCKSIZE, nOldY = (int)m_y / BLOCKSIZE;
    double xOld = m_x, yOld = m_y;
    
    int nX = (int)(m_x + FrameAbsVelocity(m_vx)) / BLOCKSIZE, nY = (int)(m_y + FrameAbsVelocity(m_vy)) / BLOCKSIZE;

    // Work out whether we have collided with a block, and if so what type.
    //  Bounce, if necessary.

    int BlockHit = GRID_EMPTY;
    if (m_vx < 0)
    {
        if (Grid[nOldY][nX] != GRID_EMPTY)
            m_vx = -m_vx;
        
        BlockHit = Grid[nOldY][nX];
    }
    else
    {
        if (Grid[nOldY][nX + 1] != GRID_EMPTY)
            m_vx = -m_vx;

        BlockHit = Grid[nOldY][nX + 1];
    }

    if (m_vy < 0)
    {
        if (Grid[nY][nOldX] != GRID_EMPTY)
            m_vy = -m_vy;

        if (BlockHit != GRID_MID)
            BlockHit = Grid[nY][nOldX];
    }
    else
    {
        if (Grid[nY + 1][nOldX] != GRID_EMPTY)
            m_vy = -m_vy;

        if (BlockHit != GRID_MID)
            BlockHit = Grid[nY + 1][nOldX];
    }

    // If we hit a mid-coloured block (i.e. the trail),
    //  the player must die.
    if (BlockHit == GRID_MID)
        g_bHasDied = TRUE;

    CSprite::Move();
}