D:/Development/Projects/X-Clone/X-Clone/trunk/Unit.cpp

Go to the documentation of this file.
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 //Unit::Unit(int playerID)
00021 //{
00022 //   Unit(playerID);
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    // true if it's the current tile
00175    // the actual map tile will say it's impassable
00176    // used for pathfinding
00177    if (_tile == t)
00178    {
00179       return true;
00180    }
00181 
00182    if ( !t.get() )
00183        return false;
00184 
00185    if ( tile->getY() == t->getY() ) // same row
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() ) // same col
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() ) // north
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() ) // south
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() ) // west
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() ) // east
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          // this assumes that maps are square - so there will always be adjacent tiles
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    //map<spMapTile, int> final;
00254    //_possibleMoves.clear();
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       //_possibleMoves[tile] = cost;
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             //tiles.push_back(_tile->getTileInDirection(**iter));
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 // provides a strict weak ordering comparison, i.e. "less than"
00418 // created for STL comparisons, but potentially useful elsewhere
00419 // if they are equal, this will return false but really it's undefined
00420 // since the order in the queue would actually take priority
00421 bool Unit::hasTurnBefore(spUnit u) const
00422 {
00423    // "_regenRate - 1" is there because this is integer math and it's flooring everything
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 

Generated on Fri Sep 22 06:00:26 2006 for X-CLONE by  doxygen 1.4.7