You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
422 lines
13 KiB
422 lines
13 KiB
#include <kapp.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tqrect.h>
|
|
#include <tqregexp.h>
|
|
#include <tqmessagebox.h>
|
|
#include <tqfile.h>
|
|
#include <tqtextstream.h>
|
|
|
|
#include "board.h"
|
|
#include "bitmaps.h"
|
|
|
|
Board::Board(int size) : TQMemArray<int> (size)
|
|
{
|
|
sz = size; // set size of board
|
|
|
|
map = "";
|
|
mapName = ""; // no map loaded so far
|
|
|
|
init(None); // initialize varibales
|
|
}
|
|
|
|
void Board::init(Image image, TQString levelName)
|
|
{
|
|
prisonEntry = OUT;
|
|
prisonExit = OUT;
|
|
fruitHome = OUT;
|
|
fruitPosition = OUT;
|
|
pacmanHome = OUT;
|
|
pacmanPosition = OUT;
|
|
for (int m = 0; m < 8; m++) {
|
|
monsterHome[m] = OUT;
|
|
monsterPosition[m] = OUT;
|
|
}
|
|
for (int e = 0; e < 8; e++) {
|
|
energizerPosition[e] = OUT;
|
|
}
|
|
for (int e = 0; e < 8; e++) {
|
|
tunnelPosition[e] = OUT;
|
|
}
|
|
|
|
fill(0);
|
|
numPoints = 0;
|
|
numEnergizers = 0;
|
|
numMonsters = 0;
|
|
numTunnels = 0;
|
|
|
|
if (!levelName.isNull() && !levelName.isEmpty())
|
|
if (mapName == levelName)
|
|
image = File;
|
|
else {
|
|
TQFile levelFile(levelName);
|
|
if (!levelFile.open(IO_ReadOnly)) {
|
|
|
|
TQString msg = i18n("The levelmap could not be constructed.\n\n"
|
|
"The file '@LEVELNAME@' does not exist,\n"
|
|
"or could not be opened for reading.");
|
|
msg.replace(TQRegExp("@LEVELNAME@"), levelName);
|
|
// TQMessageBox::information(0, i18n("Initialization Error"), msg);
|
|
printf("%s\n", msg.local8Bit().data());
|
|
} else {
|
|
map.fill(' ', BoardHeight*BoardWidth);
|
|
int height = 0;
|
|
|
|
TQTextStream levelStream(&levelFile);
|
|
while (!levelStream.eof() && height < BoardHeight) {
|
|
TQString line = levelStream.readLine();
|
|
|
|
if (line.find(TQRegExp("^ *;")) == -1) {
|
|
|
|
line.replace(TQRegExp(";.*"), ""); // strip off comments
|
|
line.replace(TQRegExp("\" *$"), ""); // strip off trailing "
|
|
line.replace(TQRegExp("^ *\""), ""); // strip off leading "
|
|
|
|
map.replace(height*BoardWidth,
|
|
(line.length() > BoardWidth) ? BoardWidth : line.length(),
|
|
line.latin1());
|
|
|
|
height++;
|
|
}
|
|
}
|
|
mapName = levelName;
|
|
levelFile.close();
|
|
image = File;
|
|
}
|
|
}
|
|
|
|
switch (image) {
|
|
case Intro : // setup(demo_bits);
|
|
break;
|
|
case Demo : setup(demo_bits);
|
|
break;
|
|
case Level : setup(demo_bits);
|
|
break;
|
|
case File : setup(reinterpret_cast<const unsigned char *>(map.latin1()));
|
|
break;
|
|
default : break;
|
|
}
|
|
}
|
|
|
|
void Board::setup(const uchar *buf)
|
|
{
|
|
for ( int index = 0; buf[index] != 0 && index < BoardWidth*BoardHeight; index++ ) {
|
|
switch (buf[index]) {
|
|
case '*' : set(index, brick); break;
|
|
case '+' : set(index, out); break;
|
|
case '#' : set(index, prison); break;
|
|
case '-' : set(index, gate); break;
|
|
case 'E' : set(index, tunnel); break;
|
|
case '.' : set(index, Point); break;
|
|
case 'o' : set(index, energizer); break;
|
|
case 'I' : set(index, prisonentry); break;
|
|
case 'O' : set(index, prisonexit); break;
|
|
case 'F' : set(index, fruithome); break;
|
|
case 'P' : set(index, pacmanhome); break;
|
|
default : if (buf[index] >= '0' && buf[index] <= '7') {
|
|
set(index, monsterhome, buf[index]-(uchar)'0');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Board::inBounds(int pos)
|
|
{
|
|
return ( pos < 0 || pos > sz-1 ? FALSE : TRUE);
|
|
}
|
|
|
|
void Board::set(int pos, Square sq, int m)
|
|
{
|
|
if (inBounds(pos))
|
|
switch (sq) {
|
|
case out : at(pos) = OUT; break;
|
|
case Point : at(pos) |= pointBit; numPoints++; break;
|
|
case tunnel : at(pos) = sq;
|
|
for (int e = 0; e < numTunnels; e++) { // if tunnel is already on board
|
|
if (tunnelPosition[e] == pos) // don't do it again.
|
|
pos = OUT;
|
|
}
|
|
if (pos != OUT) {
|
|
tunnelPosition[numTunnels] = pos;
|
|
numTunnels++;
|
|
}
|
|
break;
|
|
case energizer : at(pos) |= energizerBit;
|
|
for (int e = 0; e < numEnergizers; e++) {
|
|
if (energizerPosition[e] == pos)
|
|
pos = OUT;
|
|
}
|
|
if (pos != OUT) {
|
|
energizerPosition[numEnergizers] = pos;
|
|
numEnergizers++;
|
|
}
|
|
break;
|
|
case fruit : at(pos) |= fruitBit; fruitPosition = pos; break;
|
|
case pacman : at(pos) |= pacmanBit; pacmanPosition = pos; break;
|
|
case monster : at(pos) |= (monsterBit << m);
|
|
monsterPosition[m] = pos; break;
|
|
case prisonentry : prisonEntry = pos; at(pos) = empty; break;
|
|
case prisonexit : prisonExit = pos; at(pos) = empty; break;
|
|
case fruithome : fruitHome = pos; at(pos) = empty; break;
|
|
case pacmanhome : pacmanHome = pos; at(pos) = empty; break;
|
|
case monsterhome : monsterHome[m] = pos; at(pos) = empty;
|
|
if (m == 0 && prisonExit == OUT)
|
|
prisonExit = pos;
|
|
if (m == 1 && prisonEntry == OUT)
|
|
prisonEntry = pos;
|
|
numMonsters++;
|
|
break;
|
|
default : at(pos) = sq;
|
|
}
|
|
}
|
|
|
|
void Board::reset(int pos, Square sq, int m)
|
|
{
|
|
bool found = FALSE;
|
|
if (inBounds(pos))
|
|
switch (sq) {
|
|
case out : at(pos) = empty; break;
|
|
case Point : at(pos) &= ~ pointBit; numPoints--; break;
|
|
case energizer : at(pos) &= ~ energizerBit;
|
|
for (int e = 0; e < numEnergizers; e++) { // delete the position of the eaten
|
|
if (found) // energizer in the position array
|
|
energizerPosition[e-1] = energizerPosition[e];
|
|
if (energizerPosition[e] == pos)
|
|
found = TRUE;
|
|
}
|
|
energizerPosition[numEnergizers--] = OUT;
|
|
break;
|
|
case fruit : at(pos) &= ~ fruitBit; fruitPosition = OUT; break;
|
|
case pacman : at(pos) &= ~ pacmanBit; pacmanPosition = OUT; break;
|
|
case monster : at(pos) &= ~ (monsterBit << m);
|
|
monsterPosition[m] = OUT; break;
|
|
default : at(pos) = at(pos) & varBits;
|
|
}
|
|
}
|
|
|
|
int Board::position(Square sq, int m)
|
|
{
|
|
switch(sq) {
|
|
case prisonentry : return prisonEntry;
|
|
case prisonexit : return prisonExit;
|
|
case fruit : return fruitPosition;
|
|
case fruithome : return fruitHome;
|
|
case pacman : return pacmanPosition;
|
|
case pacmanhome : return pacmanHome;
|
|
case monster : return monsterPosition[m];
|
|
case monsterhome : return monsterHome[m];
|
|
case energizer : return energizerPosition[m];
|
|
case tunnel : return tunnelPosition[m];
|
|
default : return OUT;
|
|
}
|
|
}
|
|
|
|
bool Board::isOut(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return (at(pos) == OUT ? TRUE : FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
bool Board::isEmpty(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return ((at(pos) & fixBits) == empty ? TRUE : FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
bool Board::isBrick(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return ((at(pos) & fixBits) == brick ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isPrison(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return ((at(pos) & fixBits) == prison ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isGate(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return ((at(pos) & fixBits) == gate ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isTunnel(int pos)
|
|
{
|
|
if (inBounds(pos))
|
|
return ((at(pos) & fixBits) == tunnel ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isPoint(int pos)
|
|
{
|
|
if (inBounds(pos) && at(pos) != OUT)
|
|
return ((at(pos) & pointBit) != 0 ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isEnergizer(int pos)
|
|
{
|
|
if (inBounds(pos) && at(pos) != OUT)
|
|
return ((at(pos) & energizerBit) != 0 ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isFruit(int pos)
|
|
{
|
|
if (inBounds(pos) && at(pos) != OUT)
|
|
return ((at(pos) & fruitBit) != 0 ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isPacman(int pos)
|
|
{
|
|
if (inBounds(pos) && at(pos) != OUT)
|
|
return ((at(pos) & pacmanBit) != 0 ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isMonster(int pos)
|
|
{
|
|
if (inBounds(pos) && at(pos) != OUT)
|
|
return ((at(pos) & monsterBits) != 0 ? TRUE : FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
bool Board::isWay(int pos, int dir, Square sq) {
|
|
int p1 = move(pos, dir, 2);
|
|
if (p1 == OUT)
|
|
return (sq == out ? TRUE : FALSE);
|
|
int p2, p3;
|
|
if (dir == N || dir == S) {
|
|
p2 = move(p1, E);
|
|
p3 = move(p1, W);
|
|
} else {
|
|
p2 = move(p1, N);
|
|
p3 = move(p1, S);
|
|
}
|
|
switch (sq) {
|
|
case out : return isOut(p1) | isOut(p2) | isOut(p3);
|
|
case empty : return isEmpty(p1) & isEmpty(p2) & isEmpty(p3);
|
|
case brick : return isBrick(p1) | isBrick(p2) | isBrick(p3);
|
|
case prison : return isPrison(p1) | isPrison(p2) | isPrison(p3);
|
|
case gate : return isGate(p1) & isGate(p2) & isGate(p3);
|
|
case tunnel : return isTunnel(p1) &
|
|
(isTunnel(p2) || isEmpty(p2)) &
|
|
(isTunnel(p3) || isEmpty(p3));
|
|
default : return FALSE;
|
|
}
|
|
}
|
|
|
|
bool Board::isJump(int pos, int dir) {
|
|
switch (dir) {
|
|
case NW: return pos < BoardWidth || x(pos) == 0;
|
|
case N: return pos < BoardWidth;
|
|
case NE: return pos < BoardWidth || x(pos) == BoardWidth-1;
|
|
case W: return x(pos) == 0;
|
|
case E: return x(pos) == BoardWidth-1;
|
|
case SW: return pos >= sz-BoardWidth || x(pos) == 0;
|
|
case S: return pos >= sz-BoardWidth;
|
|
case SE: return pos >= sz-BoardWidth || x(pos) == BoardWidth-1;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int Board::move(int pos, int dir, int steps)
|
|
{
|
|
if (steps < 0) { // move backwards
|
|
dir = turn(dir); // turn around and do your steps
|
|
steps *= -1;
|
|
}
|
|
|
|
while (steps-- != 0) { // until all steps are gone
|
|
switch (dir) {
|
|
case NW: pos = pos >= BoardWidth && x(pos) > 0 ? (pos-BoardWidth)-1 : sz-1;
|
|
break;
|
|
case N: pos = pos >= BoardWidth ? pos-BoardWidth : (sz-BoardWidth)+x(pos);
|
|
break;
|
|
case NE: pos = pos >= BoardWidth && x(pos) < BoardWidth-1 ?
|
|
(pos-BoardWidth)+1 : sz-BoardWidth;
|
|
break;
|
|
case W: pos = x(pos) > 0 ? pos-1 : pos+(BoardWidth-1);
|
|
break;
|
|
case E: pos = x(pos) < BoardWidth-1 ? pos+1 : pos-(BoardWidth-1);
|
|
break;
|
|
case SW: pos = pos < sz-BoardWidth && x(pos) > 0 ? (pos+BoardWidth)-1 : BoardWidth-1;
|
|
break;
|
|
case S: pos = pos < sz-BoardWidth ? pos+BoardWidth : x(pos);
|
|
break;
|
|
case SE: pos = pos < sz-BoardWidth && x(pos) < BoardWidth-1 ? (pos+BoardWidth)+1 : 0;
|
|
break;
|
|
}
|
|
}
|
|
return pos; // here we are
|
|
}
|
|
|
|
int Board::closeup(int pos, int dir, int target)
|
|
{
|
|
if (dir == N || dir == S) {
|
|
if (x(target) < x(pos))
|
|
return W;
|
|
if (x(target) > x(pos))
|
|
return E;
|
|
} else {
|
|
if (y(target) < y(pos))
|
|
return N;
|
|
if (y(target) > y(pos))
|
|
return S;
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
int Board::x(int pos)
|
|
{
|
|
return pos % BoardWidth;
|
|
}
|
|
|
|
int Board::y(int pos)
|
|
{
|
|
return pos/BoardWidth;
|
|
}
|
|
|
|
int Board::turn(int dir)
|
|
{
|
|
switch (dir) {
|
|
case N : return S;
|
|
case NE : return SW;
|
|
case E : return W;
|
|
case SE : return NW;
|
|
case S : return N;
|
|
case SW : return NE;
|
|
case W : return E;
|
|
case NW : return SE;
|
|
default : return dir;
|
|
}
|
|
}
|
|
|
|
int Board::points()
|
|
{
|
|
return numPoints;
|
|
}
|
|
|
|
int Board::energizers()
|
|
{
|
|
return numEnergizers;
|
|
}
|
|
|
|
int Board::monsters()
|
|
{
|
|
return numMonsters;
|
|
}
|
|
|
|
int Board::tunnels()
|
|
{
|
|
return numTunnels;
|
|
}
|