einstein/cpp-source/puzzle.cpp

197 lines
4.8 KiB
C++

#include "puzzle.h"
#include "main.h"
#include "utils.h"
#include "sound.h"
#define FIELD_OFFSET_X 12
#define FIELD_OFFSET_Y 68
#define FIELD_GAP_X 4
#define FIELD_GAP_Y 4
#define FIELD_TILE_WIDTH 48
#define FIELD_TILE_HEIGHT 48
Puzzle::Puzzle(IconSet &is, SolvedPuzzle &s, Possibilities *p):
iconSet(is), solved(s)
{
possib = p;
reset();
}
Puzzle::~Puzzle()
{
}
void Puzzle::reset()
{
valid = true;
win = false;
int x, y;
SDL_GetMouseState(&x, &y);
getCellNo(x, y, hCol, hRow, subHNo);
}
void Puzzle::draw()
{
for (int i = 0; i < PUZZLE_SIZE; i++)
for (int j = 0; j < PUZZLE_SIZE; j++)
drawCell(i, j, true);
}
void Puzzle::drawCell(int col, int row, bool addToUpdate)
{
int posX = FIELD_OFFSET_X + col * (FIELD_TILE_WIDTH + FIELD_GAP_X);
int posY = FIELD_OFFSET_Y + row * (FIELD_TILE_HEIGHT + FIELD_GAP_Y);
if (possib->isDefined(col, row)) {
int element = possib->getDefined(col, row);
if (element > 0)
screen.draw(posX, posY, iconSet.getLargeIcon(row, element,
(hCol == col) && (hRow == row)));
} else {
screen.draw(posX, posY, iconSet.getEmptyFieldIcon());
int x = posX;
int y = posY + (FIELD_TILE_HEIGHT / 6);
for (int i = 0; i < 6; i++) {
if (possib->isPossible(col, row, i + 1))
screen.draw(x, y, iconSet.getSmallIcon(row, i + 1,
(hCol == col) && (hRow == row) && (i + 1 == subHNo)));
if (i == 2) {
x = posX;
y += (FIELD_TILE_HEIGHT / 3);
} else
x += (FIELD_TILE_WIDTH / 3);
}
}
if (addToUpdate)
screen.addRegionToUpdate(posX, posY, FIELD_TILE_WIDTH,
FIELD_TILE_HEIGHT);
}
void Puzzle::drawRow(int row, bool addToUpdate)
{
for (int i = 0; i < PUZZLE_SIZE; i++)
drawCell(i, row, addToUpdate);
}
bool Puzzle::onMouseButtonDown(int button, int x, int y)
{
int col, row, element;
if (! getCellNo(x, y, col, row, element))
return false;
if (! possib->isDefined(col, row)) {
/*if (button == 3) {
for (int i = 1; i <= PUZZLE_SIZE; i++)
possib->makePossible(col, row, i);
drawCell(col, row);
}
} else {*/
if (element == -1)
return false;
if (button == 1) {
if (possib->isPossible(col, row, element)) {
possib->set(col, row, element);
sound->play(L"laser.wav");
}
} else if (button == 3) {
if (possib->isPossible(col, row, element)) {
possib->exclude(col, row, element);
sound->play(L"whizz.wav");
}
/*else
possib->makePossible(col, row, element);*/
}
drawRow(row);
}
bool valid = possib->isValid(solved);
if (! valid)
onFail();
else
if (possib->isSolved() && valid)
onVictory();
return true;
}
void Puzzle::onFail()
{
if (failCommand)
failCommand->doAction();
}
void Puzzle::onVictory()
{
if (winCommand)
winCommand->doAction();
}
bool Puzzle::getCellNo(int x, int y, int &col, int &row, int &subNo)
{
col = row = subNo = -1;
if (! isInRect(x, y, FIELD_OFFSET_X, FIELD_OFFSET_Y,
(FIELD_TILE_WIDTH + FIELD_GAP_X) * PUZZLE_SIZE,
(FIELD_TILE_HEIGHT + FIELD_GAP_Y) * PUZZLE_SIZE))
return false;
x = x - FIELD_OFFSET_X;
y = y - FIELD_OFFSET_Y;
col = x / (FIELD_TILE_WIDTH + FIELD_GAP_X);
if (col * (FIELD_TILE_WIDTH + FIELD_GAP_X) + FIELD_TILE_WIDTH < x)
return false;
row = y / (FIELD_TILE_HEIGHT + FIELD_GAP_Y);
if (row * (FIELD_TILE_HEIGHT + FIELD_GAP_Y) + FIELD_TILE_HEIGHT < y)
return false;
x = x - col * (FIELD_TILE_WIDTH + FIELD_GAP_X);
y = y - row * (FIELD_TILE_HEIGHT + FIELD_GAP_Y)
- FIELD_TILE_HEIGHT / 6;
if ((y < 0) || (y >= (FIELD_TILE_HEIGHT / 3) * 2))
return true;
int cCol = x / (FIELD_TILE_WIDTH / 3);
if (cCol >= 3) {
col = row = -1;
return false;
}
int cRow = y / (FIELD_TILE_HEIGHT / 3);
subNo = cRow * 3 + cCol + 1;
return true;
}
bool Puzzle::onMouseMove(int x, int y)
{
int oldCol = hCol;
int oldRow = hRow;
int oldElement = subHNo;
getCellNo(x, y, hCol, hRow, subHNo);
if ((hCol != oldCol) || (hRow != oldRow) || (subHNo != oldElement)) {
if ((oldCol != -1) && (oldRow != -1))
drawCell(oldCol, oldRow);
if ((hCol != -1) && (hRow != -1))
drawCell(hCol, hRow);
}
return false;
}
void Puzzle::setCommands(Command *win, Command *fail)
{
winCommand = win;
failCommand = fail;
}