00001
00002
00003 #if defined( KDE2_PORT )
00004 #include <kapp.h>
00005 #include <klocale.h>
00006 #endif
00007
00008 #include <qmessagebox.h>
00009 #include <qfile.h>
00010 #include <qtextstream.h>
00011
00012 #include "board.h"
00013 #include "bitmaps.h"
00014
00015 Board::Board(int size) : QArray<int> (size)
00016 {
00017 sz = size;
00018
00019 map = "";
00020 mapName = "";
00021
00022 init(None);
00023 }
00024
00025 void Board::init(Image image, QString levelName)
00026 {
00027 prisonEntry = OUT;
00028 prisonExit = OUT;
00029 fruitHome = OUT;
00030 fruitPosition = OUT;
00031 pacmanHome = OUT;
00032 pacmanPosition = OUT;
00033 for (int m = 0; m < 8; m++) {
00034 monsterHome[m] = OUT;
00035 monsterPosition[m] = OUT;
00036 }
00037 for (int e = 0; e < 8; e++) {
00038 energizerPosition[e] = OUT;
00039 }
00040 for (int e = 0; e < 8; e++) {
00041 tunnelPosition[e] = OUT;
00042 }
00043
00044 fill(0);
00045 numPoints = 0;
00046 numEnergizers = 0;
00047 numMonsters = 0;
00048 numTunnels = 0;
00049
00050 if (!levelName.isNull() && !levelName.isEmpty())
00051 if (mapName == levelName)
00052 image = File;
00053 else {
00054 QFile levelFile(levelName);
00055 if (!levelFile.open(IO_ReadOnly)) {
00056
00057 QString msg = "The levelmap could not be constructed.\n\n"
00058 "The file '@LEVELNAME@' does not exist,\n"
00059 "or could not be opened for reading.";
00060 msg.replace(QRegExp("@LEVELNAME@"), levelName);
00061
00062 printf("%s\n", msg.data());
00063 } else {
00064 map.fill(' ', BoardHeight*BoardWidth);
00065 int height = 0;
00066
00067 QTextStream levelStream(&levelFile);
00068 while (!levelStream.eof() && height < BoardHeight) {
00069 QString line = levelStream.readLine();
00070
00071 if (line.find(QRegExp("^ *;")) == -1) {
00072
00073 line.replace(QRegExp(";.*"), "");
00074 line.replace(QRegExp("\" *$"), "");
00075 line.replace(QRegExp("^ *\""), "");
00076
00077 map.replace(height*BoardWidth,
00078 (line.length() > BoardWidth) ? BoardWidth : line.length(),
00079 line.data());
00080
00081 height++;
00082 }
00083 }
00084 mapName = levelName;
00085 levelFile.close();
00086 image = File;
00087 }
00088 }
00089
00090 switch (image) {
00091 case Intro :
00092 break;
00093 case Demo : setup(demo_bits);
00094 break;
00095 case Level : setup(demo_bits);
00096 break;
00097 case File : setup((uchar *) map.data());
00098 break;
00099 default : break;
00100 }
00101 }
00102
00103 void Board::setup(const uchar *buf)
00104 {
00105 for ( int index = 0; buf[index] != 0 && index < BoardWidth*BoardHeight; index++ ) {
00106 switch (buf[index]) {
00107 case '*' : set(index, brick); break;
00108 case '+' : set(index, out); break;
00109 case '#' : set(index, prison); break;
00110 case '-' : set(index, gate); break;
00111 case 'E' : set(index, tunnel); break;
00112 case '.' : set(index, Point); break;
00113 case 'o' : set(index, energizer); break;
00114 case 'I' : set(index, prisonentry); break;
00115 case 'O' : set(index, prisonexit); break;
00116 case 'F' : set(index, fruithome); break;
00117 case 'P' : set(index, pacmanhome); break;
00118 default : if (buf[index] >= '0' && buf[index] <= '7') {
00119 set(index, monsterhome, buf[index]-(uchar)'0');
00120 }
00121 }
00122 }
00123 }
00124
00125 bool Board::inBounds(int pos)
00126 {
00127 return ( pos < 0 || pos > sz-1 ? FALSE : TRUE);
00128 }
00129
00130 void Board::set(int pos, Square sq, int m)
00131 {
00132 if (inBounds(pos))
00133 switch (sq) {
00134 case out : at(pos) = OUT; break;
00135 case Point : at(pos) |= pointBit; numPoints++; break;
00136 case tunnel : at(pos) = sq;
00137 for (int e = 0; e < numTunnels; e++) {
00138 if (tunnelPosition[e] == pos)
00139 pos = OUT;
00140 }
00141 if (pos != OUT) {
00142 tunnelPosition[numTunnels] = pos;
00143 numTunnels++;
00144 }
00145 break;
00146 case energizer : at(pos) |= energizerBit;
00147 for (int e = 0; e < numEnergizers; e++) {
00148 if (energizerPosition[e] == pos)
00149 pos = OUT;
00150 }
00151 if (pos != OUT) {
00152 energizerPosition[numEnergizers] = pos;
00153 numEnergizers++;
00154 }
00155 break;
00156 case fruit : at(pos) |= fruitBit; fruitPosition = pos; break;
00157 case pacman : at(pos) |= pacmanBit; pacmanPosition = pos; break;
00158 case monster : at(pos) |= (monsterBit << m);
00159 monsterPosition[m] = pos; break;
00160 case prisonentry : prisonEntry = pos; at(pos) = empty; break;
00161 case prisonexit : prisonExit = pos; at(pos) = empty; break;
00162 case fruithome : fruitHome = pos; at(pos) = empty; break;
00163 case pacmanhome : pacmanHome = pos; at(pos) = empty; break;
00164 case monsterhome : monsterHome[m] = pos; at(pos) = empty;
00165 if (m == 0 && prisonExit == OUT)
00166 prisonExit = pos;
00167 if (m == 1 && prisonEntry == OUT)
00168 prisonEntry = pos;
00169 numMonsters++;
00170 break;
00171 default : at(pos) = sq;
00172 }
00173 }
00174
00175 void Board::reset(int pos, Square sq, int m)
00176 {
00177 bool found = FALSE;
00178 if (inBounds(pos))
00179 switch (sq) {
00180 case out : at(pos) = empty; break;
00181 case Point : at(pos) &= ~ pointBit; numPoints--; break;
00182 case energizer : at(pos) &= ~ energizerBit;
00183 for (int e = 0; e < numEnergizers; e++) {
00184 if (found)
00185 energizerPosition[e-1] = energizerPosition[e];
00186 if (energizerPosition[e] == pos)
00187 found = TRUE;
00188 }
00189 energizerPosition[numEnergizers--] = OUT;
00190 break;
00191 case fruit : at(pos) &= ~ fruitBit; fruitPosition = OUT; break;
00192 case pacman : at(pos) &= ~ pacmanBit; pacmanPosition = OUT; break;
00193 case monster : at(pos) &= ~ (monsterBit << m);
00194 monsterPosition[m] = OUT; break;
00195 default : at(pos) = at(pos) & varBits;
00196 }
00197 }
00198
00199 int Board::position(Square sq, int m)
00200 {
00201 switch(sq) {
00202 case prisonentry : return prisonEntry;
00203 case prisonexit : return prisonExit;
00204 case fruit : return fruitPosition;
00205 case fruithome : return fruitHome;
00206 case pacman : return pacmanPosition;
00207 case pacmanhome : return pacmanHome;
00208 case monster : return monsterPosition[m];
00209 case monsterhome : return monsterHome[m];
00210 case energizer : return energizerPosition[m];
00211 case tunnel : return tunnelPosition[m];
00212 default : return OUT;
00213 }
00214 }
00215
00216 bool Board::isOut(int pos)
00217 {
00218 if (inBounds(pos))
00219 return (at(pos) == OUT ? TRUE : FALSE);
00220 return TRUE;
00221 }
00222
00223 bool Board::isEmpty(int pos)
00224 {
00225 if (inBounds(pos))
00226 return ((at(pos) & fixBits) == empty ? TRUE : FALSE);
00227 return TRUE;
00228 }
00229
00230 bool Board::isBrick(int pos)
00231 {
00232 if (inBounds(pos))
00233 return ((at(pos) & fixBits) == brick ? TRUE : FALSE);
00234 return FALSE;
00235 }
00236
00237 bool Board::isPrison(int pos)
00238 {
00239 if (inBounds(pos))
00240 return ((at(pos) & fixBits) == prison ? TRUE : FALSE);
00241 return FALSE;
00242 }
00243
00244 bool Board::isGate(int pos)
00245 {
00246 if (inBounds(pos))
00247 return ((at(pos) & fixBits) == gate ? TRUE : FALSE);
00248 return FALSE;
00249 }
00250
00251 bool Board::isTunnel(int pos)
00252 {
00253 if (inBounds(pos))
00254 return ((at(pos) & fixBits) == tunnel ? TRUE : FALSE);
00255 return FALSE;
00256 }
00257
00258 bool Board::isPoint(int pos)
00259 {
00260 if (inBounds(pos) && at(pos) != OUT)
00261 return ((at(pos) & pointBit) != 0 ? TRUE : FALSE);
00262 return FALSE;
00263 }
00264
00265 bool Board::isEnergizer(int pos)
00266 {
00267 if (inBounds(pos) && at(pos) != OUT)
00268 return ((at(pos) & energizerBit) != 0 ? TRUE : FALSE);
00269 return FALSE;
00270 }
00271
00272 bool Board::isFruit(int pos)
00273 {
00274 if (inBounds(pos) && at(pos) != OUT)
00275 return ((at(pos) & fruitBit) != 0 ? TRUE : FALSE);
00276 return FALSE;
00277 }
00278
00279 bool Board::isPacman(int pos)
00280 {
00281 if (inBounds(pos) && at(pos) != OUT)
00282 return ((at(pos) & pacmanBit) != 0 ? TRUE : FALSE);
00283 return FALSE;
00284 }
00285
00286 bool Board::isMonster(int pos)
00287 {
00288 if (inBounds(pos) && at(pos) != OUT)
00289 return ((at(pos) & monsterBits) != 0 ? TRUE : FALSE);
00290 return FALSE;
00291 }
00292
00293 bool Board::isWay(int pos, int dir, Square sq) {
00294 int p1 = move(pos, dir, 2);
00295 if (p1 == OUT)
00296 return (sq == out ? TRUE : FALSE);
00297 int p2, p3;
00298 if (dir == N || dir == S) {
00299 p2 = move(p1, E);
00300 p3 = move(p1, W);
00301 } else {
00302 p2 = move(p1, N);
00303 p3 = move(p1, S);
00304 }
00305 switch (sq) {
00306 case out : return isOut(p1) | isOut(p2) | isOut(p3);
00307 case empty : return isEmpty(p1) & isEmpty(p2) & isEmpty(p3);
00308 case brick : return isBrick(p1) | isBrick(p2) | isBrick(p3);
00309 case prison : return isPrison(p1) | isPrison(p2) | isPrison(p3);
00310 case gate : return isGate(p1) & isGate(p2) & isGate(p3);
00311 case tunnel : return isTunnel(p1) &
00312 (isTunnel(p2) || isEmpty(p2)) &
00313 (isTunnel(p3) || isEmpty(p3));
00314 default : return FALSE;
00315 }
00316 }
00317
00318 bool Board::isJump(int pos, int dir) {
00319 switch (dir) {
00320 case NW: return pos < BoardWidth || x(pos) == 0;
00321 case N: return pos < BoardWidth;
00322 case NE: return pos < BoardWidth || x(pos) == BoardWidth-1;
00323 case W: return x(pos) == 0;
00324 case E: return x(pos) == BoardWidth-1;
00325 case SW: return pos >= sz-BoardWidth || x(pos) == 0;
00326 case S: return pos >= sz-BoardWidth;
00327 case SE: return pos >= sz-BoardWidth || x(pos) == BoardWidth-1;
00328 }
00329 return FALSE;
00330 }
00331
00332 int Board::move(int pos, int dir, int steps)
00333 {
00334 if (steps < 0) {
00335 dir = turn(dir);
00336 steps *= -1;
00337 }
00338
00339 while (steps-- != 0) {
00340 switch (dir) {
00341 case NW: pos = pos >= BoardWidth && x(pos) > 0 ? (pos-BoardWidth)-1 : sz-1;
00342 break;
00343 case N: pos = pos >= BoardWidth ? pos-BoardWidth : (sz-BoardWidth)+x(pos);
00344 break;
00345 case NE: pos = pos >= BoardWidth && x(pos) < BoardWidth-1 ?
00346 (pos-BoardWidth)+1 : sz-BoardWidth;
00347 break;
00348 case W: pos = x(pos) > 0 ? pos-1 : pos+(BoardWidth-1);
00349 break;
00350 case E: pos = x(pos) < BoardWidth-1 ? pos+1 : pos-(BoardWidth-1);
00351 break;
00352 case SW: pos = pos < sz-BoardWidth && x(pos) > 0 ? (pos+BoardWidth)-1 : BoardWidth-1;
00353 break;
00354 case S: pos = pos < sz-BoardWidth ? pos+BoardWidth : x(pos);
00355 break;
00356 case SE: pos = pos < sz-BoardWidth && x(pos) < BoardWidth-1 ? (pos+BoardWidth)+1 : 0;
00357 break;
00358 }
00359 }
00360 return pos;
00361 }
00362
00363 int Board::closeup(int pos, int dir, int target)
00364 {
00365 if (dir == N || dir == S) {
00366 if (x(target) < x(pos))
00367 return W;
00368 if (x(target) > x(pos))
00369 return E;
00370 } else {
00371 if (y(target) < y(pos))
00372 return N;
00373 if (y(target) > y(pos))
00374 return S;
00375 }
00376 return dir;
00377 }
00378
00379 int Board::x(int pos)
00380 {
00381 return pos % BoardWidth;
00382 }
00383
00384 int Board::y(int pos)
00385 {
00386 return pos/BoardWidth;
00387 }
00388
00389 int Board::turn(int dir)
00390 {
00391 switch (dir) {
00392 case N : return S;
00393 case NE : return SW;
00394 case E : return W;
00395 case SE : return NW;
00396 case S : return N;
00397 case SW : return NE;
00398 case W : return E;
00399 case NW : return SE;
00400 default : return dir;
00401 }
00402 }
00403
00404 int Board::points()
00405 {
00406 return numPoints;
00407 }
00408
00409 int Board::energizers()
00410 {
00411 return numEnergizers;
00412 }
00413
00414 int Board::monsters()
00415 {
00416 return numMonsters;
00417 }
00418
00419 int Board::tunnels()
00420 {
00421 return numTunnels;
00422 }