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.
tdegames/ksokoban/Map.cpp

205 lines
4.5 KiB

/*
* ksokoban - a Sokoban game for KDE
* Copyright (C) 1998 Anders Widell <d95-awi@nada.kth.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "Map.h"
Map::Map() : xpos_(-1), ypos_(-1), width_(0), height_(0), objectsLeft_(-1) {
}
void
Map::map (int x, int y, int val) {
assert (x>=0 && x<=MAX_X && y>=0 && y<=MAX_Y);
if ((map (x, y) & (OBJECT | GOAL)) == OBJECT) objectsLeft_--;
if ((val & (OBJECT | GOAL)) == OBJECT) objectsLeft_++;
currentMap_[y+1][x+1] = val;
if (val != 0) {
if (width_ <= x) width_ = x+1;
if (height_ <= y) height_ = y+1;
}
}
void
Map::setMap (int x, int y, int bits) {
assert ((map (x, y) & bits) == 0);
if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_--;
assert (objectsLeft_ >= 0);
currentMap_[y+1][x+1] |= bits;
if (bits != 0) {
if (width_ <= x) width_ = x+1;
if (height_ <= y) height_ = y+1;
}
}
void
Map::clearMap (int x, int y, int bits) {
assert ((map (x, y) & bits) == bits);
if (goal (x, y) && ((bits & OBJECT) == OBJECT)) objectsLeft_++;
currentMap_[y+1][x+1] &= ~bits;
}
void
Map::clearMap () {
memset (currentMap_, 0, (MAX_Y+3)*(MAX_X+3)*sizeof (char));
objectsLeft_ = 0;
width_ = height_ = 0;
}
bool
Map::fillFloor (int x, int y) {
if (badCoords (x, y)) return false;
if ((currentMap_[y+1][x+1] & (WALL|FLOOR)) != 0) return true;
currentMap_[y+1][x+1] |= FLOOR;
bool a = fillFloor (x, y-1);
bool b = fillFloor (x, y+1);
bool c = fillFloor (x-1, y);
bool d = fillFloor (x+1, y);
return a && b && c && d;
}
bool
Map::step (int _x, int _y) {
assert (!badCoords (xpos_, ypos_));
assert (empty (xpos_, ypos_));
int xd=0, yd=0;
if (_x < xpos_) xd = -1;
if (_x > xpos_) xd = 1;
if (_y < ypos_) yd = -1;
if (_y > ypos_) yd = 1;
if (badDelta (xd, yd) || badCoords (_x, _y)) return false;
int x=xpos_, y=ypos_;
do {
x += xd;
y += yd;
if (!empty (x, y)) return false;
} while (!(x==_x && y==_y));
xpos_ = _x;
ypos_ = _y;
return true;
}
bool
Map::push (int _x, int _y) {
assert (!badCoords (xpos_, ypos_));
assert (empty (xpos_, ypos_));
int xd=0, yd=0;
if (_x < xpos_) xd = -1;
if (_x > xpos_) xd = 1;
if (_y < ypos_) yd = -1;
if (_y > ypos_) yd = 1;
if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false;
int x=xpos_+xd, y=ypos_+yd;
if (!object (x, y)) return false;
if (!empty (_x+xd, _y+yd)) return false;
while (!(x==_x && y==_y)) {
x += xd;
y += yd;
if (!empty (x, y)) return false;
}
clearMap (xpos_+xd, ypos_+yd, OBJECT);
setMap (_x+xd, _y+yd, OBJECT);
xpos_ = _x;
ypos_ = _y;
return true;
}
bool
Map::unstep (int _x, int _y) {
return Map::step (_x, _y);
}
bool
Map::unpush (int _x, int _y) {
assert (!badCoords (xpos_, ypos_));
assert (empty (xpos_, ypos_));
int xd=0, yd=0;
if (_x < xpos_) xd = -1;
if (_x > xpos_) xd = 1;
if (_y < ypos_) yd = -1;
if (_y > ypos_) yd = 1;
if (badDelta (xd, yd) || badCoords (_x+xd, _y+yd)) return false;
int x=xpos_, y=ypos_;
if (!object (x-xd, y-yd)) return false;
do {
x += xd;
y += yd;
if (!empty (x, y)) return false;
} while (!(x==_x && y==_y));
clearMap (xpos_-xd, ypos_-yd, OBJECT);
setMap (_x-xd, _y-yd, OBJECT);
xpos_ = _x;
ypos_ = _y;
return true;
}
void
Map::printMap(void) {
for (int y=0; y<height_; y++) {
for (int x=0; x<width_; x++) {
switch (map (x, y) & ~FLOOR) {
case WALL:
printf("#");
break;
case GOAL:
printf("%c", x==xpos_ && y==ypos_ ? '+' : '.');
break;
case OBJECT:
printf("$");
break;
case OBJECT|GOAL:
printf("*");
break;
case 0:
printf("%c", x==xpos_ && y==ypos_ ? '@' : ' ');
break;
default:
printf("<%X>", map(x,y)&FLOOR);
break;
}
}
printf ("\n");
}
}