00001 #include "Unit.h"
00002 #include "Display.h"
00003
00004 #define UNIT_IMAGE "images/unit.png"
00005 #define UNIT_PATH_IMAGE "images/unit_path.png"
00006 #define UNIT_PATH_END_IMAGE "images/unit_path_end.png"
00007 #define UNIT_ACTIVE_IMAGE "images/unit_active.png"
00008 #define UNIT_SELECTED_IMAGE "images/unit_selected.png"
00009
00010 SDL_Surface* Unit::_image = NULL;
00011 SDL_Surface* Unit::_pathImage = NULL;
00012 SDL_Surface* Unit::_pathEndImage = NULL;
00013 SDL_Surface* Unit::_selectedImage = NULL;
00014 SDL_Surface* Unit::_activeImage = NULL;
00015
00016 int Unit::_maxActionPoints = 50;
00017 spUnit Unit::_activeUnit;
00018 spUnit Unit::_selectedUnit;
00019
00020
00021
00022
00023
00024
00025 spUnit Unit::makeUnit(int playerID)
00026 {
00027 return makeUnit(playerID, spMapTile());
00028 }
00029
00030 spUnit Unit::makeUnit(int playerID, spMapTile tile)
00031 {
00032 if (tile->isPassable())
00033 {
00034 spUnit unit = spUnit(new Unit(playerID, tile));
00035 unit->_weak = unit;
00036 unit->_tile->addUnit(unit);
00037 return unit;
00038 }
00039 return spUnit();
00040 }
00041
00042 Unit::Unit(int playerID, spMapTile tile) :
00043 _playerID(playerID),
00044 _actionPoints(_maxActionPoints),
00045 _regenRate(10)
00046 {
00047 static bool mapped = false;
00048 if (!mapped)
00049 {
00050 _image = Display::instance().loadImage(UNIT_IMAGE);
00051 _pathImage = Display::instance().loadImage(UNIT_PATH_IMAGE);
00052 _pathEndImage = Display::instance().loadImage(UNIT_PATH_END_IMAGE);
00053 _selectedImage = Display::instance().loadImage(UNIT_SELECTED_IMAGE);
00054 _activeImage = Display::instance().loadImage(UNIT_ACTIVE_IMAGE);
00055
00056 mapped = true;
00057 }
00058 _tile = tile;
00059 }
00060
00061 Unit::~Unit()
00062 {
00063 }
00064
00065 int Unit::getPlayerID() const
00066 {
00067 return _playerID;
00068 }
00069
00070 int Unit::getX() const
00071 {
00072 return _tile->getX();
00073 }
00074
00075 int Unit::getY() const
00076 {
00077 return _tile->getY();
00078 }
00079
00080 void Unit::draw(Point position, Point dimensions) const
00081 {
00082 Display& d = Display::instance();
00083 if (this == _selectedUnit.get())
00084 {
00085 d.draw(position.x + dimensions.x/2 -_selectedImage->w/2,
00086 position.y + dimensions.y/2 - _selectedImage->h/2,
00087 _selectedImage);
00088
00089 ostringstream stream;
00090 stream << "Action Points: " << _actionPoints;
00091 d.draw(d.getScreenWidth() - 150, 5, stream.str());
00092
00093 }
00094 if (this == _activeUnit.get())
00095 {
00096 d.draw(position.x + dimensions.x/2 -_activeImage->w/2,
00097 position.y + dimensions.y/2 - _activeImage->h/2,
00098 _activeImage);
00099 }
00100
00101 d.draw(position.x + dimensions.x/2 - _image->w/2,
00102 position.y + dimensions.y/2 - _image->h + 5,
00103 _image);
00104 }
00105
00106 bool Unit::isPassable() const
00107 {
00108 return false;
00109 }
00110
00111 void Unit::wait()
00112 {
00113 _actionPoints = max(_actionPoints - 50, 0);
00114 }
00115
00116 void Unit::move(Direction dir)
00117 {
00118 if (canMoveInDirection(dir))
00119 {
00120 move(_tile->getTileInDirection(dir));
00121 }
00122 }
00123
00124 void Unit::move(spMapTile tile)
00125 {
00126 if (tile->isPassable())
00127 {
00128 _tile->removeUnit();
00129 _tile = tile;
00130 _tile->addUnit(spUnit(_weak));
00131 updatePossibleMoves();
00132 }
00133 }
00134
00135 bool Unit::canMoveInDirection( Direction dir )
00136 {
00137 return canMoveInDirection(_tile, dir, _actionPoints);
00138 }
00139
00140 bool Unit::canMoveInDirection( spMapTile tile, Direction dir, int points )
00141 {
00142 static map<Direction, Direction*> clockwise;
00143 static map<Direction, Direction*> counterClockwise;
00144
00145 if (clockwise.empty())
00146 {
00147 clockwise[Direction::N] = &Direction::NE;
00148 clockwise[Direction::NE] = &Direction::E;
00149 clockwise[Direction::E] = &Direction::SE;
00150 clockwise[Direction::SE] = &Direction::S;
00151 clockwise[Direction::S] = &Direction::SW;
00152 clockwise[Direction::SW] = &Direction::W;
00153 clockwise[Direction::W] = &Direction::NW;
00154 clockwise[Direction::NW] = &Direction::N;
00155 }
00156
00157 if (counterClockwise.empty())
00158 {
00159 counterClockwise[Direction::N] = &Direction::NW;
00160 counterClockwise[Direction::NE] = &Direction::N;
00161 counterClockwise[Direction::E] = &Direction::NE;
00162 counterClockwise[Direction::SE] = &Direction::E;
00163 counterClockwise[Direction::S] = &Direction::SE;
00164 counterClockwise[Direction::SW] = &Direction::S;
00165 counterClockwise[Direction::W] = &Direction::SW;
00166 counterClockwise[Direction::NW] = &Direction::W;
00167 }
00168
00169 int x = getX() + dir.offset().x;
00170 int y = getY() + dir.offset().y;
00171
00172 spMapTile t = tile->getTileInDirection(dir);
00173
00174
00175
00176
00177 if (_tile == t)
00178 {
00179 return true;
00180 }
00181
00182 if ( !t.get() )
00183 return false;
00184
00185 if ( tile->getY() == t->getY() )
00186 {
00187 if ( tile->getX() < t->getX() )
00188 {
00189 if ( !tile->isPassable(Direction::SW) )
00190 return false;
00191 }
00192 else if ( !tile->isPassable(Direction::NE) )
00193 return false;
00194 }
00195 if ( tile->getX() == t->getX() )
00196 {
00197 if ( tile->getY() < t->getY() )
00198 {
00199 if ( !tile->isPassable(Direction::SE) )
00200 return false;
00201 }
00202 else if ( !tile->isPassable(Direction::NW) )
00203 return false;
00204 }
00205 if ( tile->getX() < t->getX() && tile->getY() < t->getY() )
00206 {
00207 if ( !tile->isPassable(Direction::NE) || !tile->isPassable(Direction::NW) || !t->isPassable(Direction::SE) || !t->isPassable(Direction::SW) )
00208 return false;
00209 }
00210 if ( tile->getX() > t->getX() && tile->getY() > t->getY() )
00211 {
00212 if ( !tile->isPassable(Direction::SE) || !tile->isPassable(Direction::SW) || !t->isPassable(Direction::NE) || !t->isPassable(Direction::NW) )
00213 return false;
00214 }
00215 if ( tile->getX() > t->getX() && tile->getY() < t->getY() )
00216 {
00217 if ( !tile->isPassable(Direction::NW) || !tile->isPassable(Direction::SW) || !t->isPassable(Direction::NE) || !t->isPassable(Direction::SE) )
00218 return false;
00219 }
00220 if ( tile->getX() < t->getX() && tile->getY() > t->getY() )
00221 {
00222 if ( !tile->isPassable(Direction::NE) || !tile->isPassable(Direction::SE) || !t->isPassable(Direction::NW) || !t->isPassable(Direction::SW) )
00223 return false;
00224 }
00225
00226 bool ok = false;
00227 if (t.get() && t->isPassable() && points >= tile->getMoveCost(dir))
00228 {
00229 if (dir.isCardinal())
00230 {
00231
00232 if (tile->getTileInDirection(*(clockwise[dir]))->isPassable() &&
00233 tile->getTileInDirection(*(counterClockwise[dir]))->isPassable())
00234 {
00235 ok = true;
00236 }
00237 }
00238 else
00239 {
00240 ok = true;
00241 }
00242 }
00243 return ok;
00244 }
00245
00246 map<spMapTile, int> Unit::getPossibleMoves()
00247 {
00248 return _possibleMoves;
00249 }
00250
00251 void Unit::updatePossibleMoves()
00252 {
00253
00254
00255 map<spMapTile, int> temp;
00256 queue<spMapTile> waiting;
00257
00258 waiting.push(_tile);
00259 temp[_tile] = 0;
00260
00261 while (!waiting.empty())
00262 {
00263 spMapTile tile = waiting.front();
00264 int cost = temp[tile];
00265 int remaining = _actionPoints - cost;
00266
00267
00268 waiting.pop();
00269
00270 vector<const Direction*> dirs = Direction::getAllDirections();
00271 vector<const Direction*>::const_iterator iter;
00272 for(iter = dirs.begin(); iter != dirs.end(); ++iter)
00273 {
00274 if (canMoveInDirection(tile, **iter, remaining))
00275 {
00276 spMapTile nextTile = tile->getTileInDirection(**iter);
00277 int nextCost = tile->getMoveCost(**iter) + cost;
00278 if (temp.count(nextTile) == 0)
00279 {
00280 waiting.push(nextTile);
00281 temp[nextTile] = nextCost;
00282 }
00283 else if (temp[nextTile] > nextCost)
00284 {
00285 temp[nextTile] = nextCost;
00286 }
00287
00288
00289 }
00290 }
00291 }
00292
00293 _possibleMoves = temp;
00294 }
00295
00296 void Unit::computeMovePath(spMapTile dest)
00297 {
00298 _movementPath.clear();
00299 map<spMapTile, int>::iterator iter = _possibleMoves.find(dest);
00300 if (iter != _possibleMoves.end())
00301 {
00302 _movementPath.push_front(*iter);
00303 pair<spMapTile, int> next = *iter;
00304 while (true)
00305 {
00306 next = computeMovePathHelper(next.first);
00307 if (next.first == _tile)
00308 {
00309 break;
00310 }
00311 else
00312 {
00313 _movementPath.push_front(next);
00314 }
00315 }
00316 }
00317 }
00318
00319 pair<spMapTile, int> Unit::computeMovePathHelper(spMapTile current)
00320 {
00321 pair<spMapTile, int> lowest(spMapTile(), numeric_limits<int>::max());
00322 vector<const Direction*> dirs = Direction::getAllDirections();
00323 vector<const Direction*>::const_iterator iter;
00324 for(iter = dirs.begin(); iter != dirs.end(); ++iter)
00325 {
00326 if (canMoveInDirection(current, **iter, numeric_limits<int>::max()))
00327 {
00328 spMapTile adjacent = current->getTileInDirection(**iter);
00329 if (adjacent.get())
00330 {
00331 map<spMapTile, int>::iterator iter = _possibleMoves.find(adjacent);
00332 if (iter != _possibleMoves.end() && (*iter).second < lowest.second)
00333 {
00334 lowest = *iter;
00335 }
00336 }
00337 }
00338 }
00339 return lowest;
00340 }
00341
00342 bool Unit::hasMovePath() const
00343 {
00344 return !_movementPath.empty();
00345 }
00346
00347 void Unit::moveAlongPath( bool teleport )
00348 {
00349 if (!hasMovePath())
00350 {
00351 return;
00352 }
00353
00354 if (teleport)
00355 {
00356 _actionPoints -= _movementPath.back().second;
00357 move(_movementPath.back().first);
00358 clearMovePath();
00359 }
00360 else
00361 {
00362 _actionPoints = _maxActionPoints - _movementPath.front().second;
00363 move(_movementPath.front().first);
00364 _movementPath.pop_front();
00365 }
00366 }
00367
00368 void Unit::drawMovePath(Point offset) const
00369 {
00370 list<pair<spMapTile, int> >::const_iterator iter;
00371 for (iter = _movementPath.begin(); iter != _movementPath.end(); ++iter)
00372 {
00373 SDL_Surface* img = NULL;
00374 if (*iter == _movementPath.back())
00375 {
00376 img = _pathEndImage;
00377 }
00378 else
00379 {
00380 img = _pathImage;
00381 }
00382
00383 Display::instance().draw((*iter).first->getCenterX() - img->w/2 - offset.x,
00384 (*iter).first->getCenterY() - img->h/2 - offset.y,
00385 img);
00386 }
00387 }
00388
00389 void Unit::clearMovePath()
00390 {
00391 _movementPath.clear();
00392 }
00393
00394 const spMapTile Unit::getDestination() const
00395 {
00396 if (hasMovePath())
00397 {
00398 return _movementPath.back().first;
00399 }
00400 else
00401 {
00402 return spMapTile();
00403 }
00404 }
00405
00406 bool Unit::hasMaxActionPoints() const
00407 {
00408 return _actionPoints == _maxActionPoints;
00409 }
00410
00411 void Unit::regenActionPoints()
00412 {
00413 _actionPoints = min(_actionPoints + _regenRate, _maxActionPoints);
00414 }
00415
00416
00417
00418
00419
00420
00421 bool Unit::hasTurnBefore(spUnit u) const
00422 {
00423
00424 int thisSteps = (_maxActionPoints - _actionPoints + _regenRate - 1) / _regenRate;
00425 int thatSteps = (_maxActionPoints - u->_actionPoints + u->_regenRate - 1) / u->_regenRate;
00426
00427 return thisSteps < thatSteps;
00428 }
00429
00430 void Unit::markActive()
00431 {
00432 _activeUnit = spUnit(_weak);
00433 }
00434
00435 void Unit::clearActive()
00436 {
00437 _activeUnit = spUnit();
00438 }
00439
00440 void Unit::markSelected()
00441 {
00442 _selectedUnit = spUnit(_weak);
00443 }
00444
00445 void Unit::clearSelected()
00446 {
00447 _selectedUnit = spUnit();
00448 }
00449
00450 spUnit Unit::getSelectedUnit()
00451 {
00452 return _selectedUnit;
00453 }
00454