// Shape.cpp: implementation of the CShape class.
//
//////////////////////////////////////////////////////////////////////
#include <windows.h>
#include "BlockList.h"
#include "FlooredBlocks.h"
#include "Shape.h"
#include "resource.h"
extern HINSTANCE g_hInstance;
const short CShape::m_pStockShapes[] = {
11, // No Of shapes in the array
2 /*No of orientation shapes */, 4 /*No Of blocks for this shape*/,
2,1, 2,2, 3,2, 3,3, // O
1,2, 2,2, 2,1, 3,1, // OO
// O
0, // Each shape ends with a 0, Takes out the maths challenge :)
2,4,
1,2, 2,2, 3,2, 4,2, // OOOO
2,1, 2,2, 2,3, 2,4,
0,
2,4,
2,1, 2,2, 1,2, 1,3, // O
1,1, 2,1, 2,2, 3,2, // OO
0, // O
1,4,
2,1, 3,1, 3,2, 2,2, // OO
0, // OO
4,4,
2,2, 3,2, 2,3, 2,4, // OO
2,2, 2,3, 3,3, 4,3, // O
3,1, 3,2, 2,3, 3,3, // O
1,2, 2,2, 3,2, 3,3,
0,
4,4,
2,1, 2,2, 2,3, 3,3, // O
1,3, 2,3, 3,3, 3,2, // O
2,2, 3,2, 3,3, 3,4, // OO
2,2, 3,2, 4,2, 2,3,
0,
4,4,
2,1, 1,2, 2,2, 3,2, // O
2,1, 1,2, 2,2, 2,3, // OOO
1,2, 2,2, 3,2, 2,3, //
2,1, 2,2, 3,2, 2,3,
0,
/////////////////////// Crazy //////////////////////
1,4,
2,1,1,2,3,2,2,3, // O
0, // O O
// O
1,8, // OOO
1,1,2,1,3,1, 1,2,3,2, 1,3,2,3,3,3, // O O
0, // OOO
4,5, // OOO
1,1,2,1,3,1, 1,2,3,2, // O O
1,1,2,1, 1,2, 1,3,2,3,
1,2,1,3,2,3,3,3, 3,2,
2,1,3,1,3,2,2,3,3,3,
0,
1,5,
2,1, 1,2, 2,2, 3,2, 2,3, // O
// OOO
// O
0,
};
short CShape::s_nNoOfShapes =0;
short CShape::s_cShapesArrayUsage=0;
short CShape::s_nMaxNoOfShapesAllowed=0;
const short** CShape::s_pShapes = NULL;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CShape::CShape(CFlooredBlocks* pFlooredBlocks, const short* pShapes):m_nX(0), m_nY(0)
{
m_pFlooredBlocks = pFlooredBlocks;
if (s_cShapesArrayUsage == 0) {
s_nNoOfShapes = *pShapes;
if (s_nMaxNoOfShapesAllowed == 0)
s_nMaxNoOfShapesAllowed = s_nNoOfShapes;
s_pShapes = new const short*[ s_nNoOfShapes];
if (s_pShapes == NULL) {
OutputDebugString("Failed to allocate memory to help the pointer to shape array\n");
return;
}
const short* pCurrShape = pShapes + 1; // +1 to go past the No of shapes
for (short nI =0; nI < s_nNoOfShapes ; nI++)
{
s_pShapes[nI]= pCurrShape;
while (*pCurrShape++); // Go to the next shape.
}
}
s_cShapesArrayUsage++; // Increment the array usage
/* if s_nMaxNoOfShapesAllowed is out of range set it to Total No of shapes */
if (s_nMaxNoOfShapesAllowed < 0 && s_nMaxNoOfShapesAllowed > s_nNoOfShapes) {
s_nMaxNoOfShapesAllowed = s_nNoOfShapes;
}
}
CShape::~CShape()
{
s_cShapesArrayUsage--; // Decrement the array usage
if (s_cShapesArrayUsage == 0 ) { // If no one is using it delete the array
delete[] s_pShapes;
s_pShapes = NULL;
}
}
bool CShape::CreateRandShape(short nX, short nY)
{
m_nColor = rand() % NUM_COLORS;
m_nShape = rand() % s_nMaxNoOfShapesAllowed;
m_nRotate = 0;
m_nX = nX;
m_nY = nY;
return CreateShape();
}
//////////////////////////////////////////////////////////
// Creates a shape using the Shape array information
// Creates a list of blocks and gives them the coordinates
// from the array.
//////////////////////////////////////////////////////////
bool CShape::CreateShape()
{
const short* pShape = s_pShapes[m_nShape];
SBlock Block;
m_nTotalRotate = *pShape++;
short nNoOfBlocks = *pShape++;
pShape+= m_nRotate * nNoOfBlocks * 2;
const short* pShapeSave = pShape; // Save the pointer
// Check for Boundary and Collusion.
for (int nI = 0 ; nI < nNoOfBlocks ; nI++) {
Block.nX = *pShape + m_nX;
pShape++;
Block.nY = *pShape + m_nY;
pShape++;
if (Block.nX < m_pFlooredBlocks->m_rcBoundary.left ||
Block.nX > m_pFlooredBlocks->m_rcBoundary.right)
return false;
if (Block.nY > m_pFlooredBlocks->m_rcBoundary.bottom ||
Block.nY < m_pFlooredBlocks->m_rcBoundary.top)
return false;
if (m_pFlooredBlocks->IsOccupied(Block.nX,Block.nY))
return false;
}
pShape = pShapeSave; // Use the saved pointer
Destroy();
for (nI = 0 ; nI < nNoOfBlocks ; nI++) {
Block.nColor = m_nColor;
Block.nX = *pShape;
pShape++;
Block.nY = *pShape;
pShape++;
Add(Block);
}
return true;
}
void CShape::Display()
{
CBlockList::Display(m_nX, m_nY);
}
bool CShape::MoveTo(short nX, short nY)
{
m_nX = nX;
m_nY = nY;
return true;
}
//////////////////////////////////
// Dumps the List to debugger
///////////////////////////////////
void CShape::dbgDisplay()
{
CBlockList::dbgDisplay();
}
bool CShape::MoveLeft()
{
if (IsContained(m_pFlooredBlocks->m_rcBoundary, m_nX-1, m_nY)) {
if (m_pFlooredBlocks->IsOccupied(*this, m_nX-1, m_nY) == false) {
m_nX--;
return true;
}
}
return false;
}
bool CShape::MoveRight()
{
if (IsContained(m_pFlooredBlocks->m_rcBoundary, m_nX+1, m_nY)) {
if (m_pFlooredBlocks->IsOccupied(*this, m_nX+1, m_nY) == false) {
m_nX++;
return true;
}
}
return false;
}
bool CShape::MoveDown()
{
if (IsContained(m_pFlooredBlocks->m_rcBoundary, m_nX, m_nY+1)) {
if (m_pFlooredBlocks->IsOccupied(*this, m_nX, m_nY+1) == false) {
m_nY++;
return true;
}
}
return false;
}
bool CShape::MoveUp()
{
if (IsContained(m_pFlooredBlocks->m_rcBoundary, m_nX, m_nY-1)) {
m_nY--;
return true;
}
return false;
}
bool CShape::Rotate()
{
short nRotate = m_nRotate;
m_nRotate++;
if (m_nRotate == m_nTotalRotate)
m_nRotate = 0;
if (CreateShape() == false)
m_nRotate = nRotate;
return true;
}
void CShape::NextShape()
{
m_nShape += 1;
if (m_nShape == s_nMaxNoOfShapesAllowed)
m_nShape = 0;
m_nRotate =0;
Destroy();
CreateShape();
}
////////////////////////////////////////////////////
// Check if the Block offset by X ,Y is within
// given boundary
////////////////////////////////////////////////////
bool CShape::IsContained(RECT rcBoundary, short nX, short nY)
{
SNODE* pCurr = m_pListHead->pNext;
while (pCurr) {
SBlock Block= pCurr->Block;
if ((Block.nX + nX) < rcBoundary.left || (Block.nX + nX) > rcBoundary.right)
return false;
if ((Block.nY + nY) > rcBoundary.bottom || (Block.nY + nY) < rcBoundary.top)
return false;
pCurr=pCurr->pNext;
}
return true;
}
/////////////////////////////////////////////
// Convert to actual coordinates in space
/////////////////////////////////////////////
void CShape::ConvertToSpaceCoord()
{
SNODE* pCurr = m_pListHead->pNext;
while (pCurr) {
pCurr->Block.nX =pCurr->Block.nX + m_nX;
pCurr->Block.nY =pCurr->Block.nY + m_nY;
pCurr= pCurr->pNext;
}
}
//////////////////////////////////////////////////////////////////
// This number can be set to limit the shapes that will be
// used from the array.
// This way some crazy shapes can be added to the end of the
// array and only be used if the user switches to the crazy mode.
/////////////////////////////////////////////////////////////////
bool CShape::SetMaxNoOfShapesAllowed(short nMax /*= s_nNoOfShapes*/)
{
if (s_cShapesArrayUsage ==0) {// No objects are created so s_nNoShapes may be 0
// because the constructor may not have been called yet
// Testing on s_nMaxNoOfShapesAllowed is done in the constructor
s_nMaxNoOfShapesAllowed = nMax;
}
if (nMax > 0 && nMax <= s_nNoOfShapes) {
s_nMaxNoOfShapesAllowed = nMax;
return true;
}
return false;
}