Unit* Map::CreateUnit( UnitType* unitType, Faction* owner, const Vec2s& tilePos, int health, int ammo, int supplies ) { // Create a new Unit. Unit* unit = new Unit(); // Load Unit properties. unit->SetUnitType( unitType ); unit->SetOwner( owner ); // Get the Tile where the Unit will be placed. Iterator tile = GetTile( tilePos ); assertion( tile.IsValid(), "Cannot create Unit at invalid Tile (%d,%d)!", tilePos.x, tilePos.y ); assertion( tile->IsEmpty(), "Cannot create Unit at Tile (%d,%d) because the Tile is occupied by another Unit!", tilePos.x, tilePos.y ); // Set the health and ammo for the Unit. if( health >= 0 ) { unit->SetHealth( health ); } else { unit->ResetHealth(); } if( ammo >= 0 ) { unit->SetAmmo( ammo ); } else { unit->ResetAmmo(); } if( supplies >= 0 ) { unit->SetSupplies( supplies ); } else { unit->ResetSupplies(); } // Initialize the Unit. unit->Init( this, tile ); // Place the Unit into the Tile. tile->SetUnit( unit ); // Add the Unit to the list of Units. mUnits.push_back( unit ); return unit; }
void Map::FindBestPathToTile( const Unit* unit, const Vec2s& tilePos, Path& result ) { std::vector< PrimaryDirection > reverseDirections; int searchIndex = ReserveSearchIndex(); // Clear the list of results. result.Clear(); result.SetOrigin( unit->GetTilePos() ); // Clear the open list. mOpenList.clear(); // Get the Unit's current Tile and type. Iterator originTile = unit->GetTile(); UnitType* unitType = unit->GetUnitType(); MovementType* movementType = unit->GetMovementType(); // Get the starting movement range of the Unit. int movementRange = unit->GetMovementRange(); // Add the origin tile to the open list. originTile->Open( searchIndex ); originTile->SetPreviousTileDirection( PrimaryDirection::NONE ); originTile->SetBestTotalCostToEnter( 0 ); mOpenList.insert( 0, originTile ); while( !mOpenList.isEmpty() ) { // Pop the first element off the open list. Map::Iterator tile = mOpenList.popMinElement(); if( tile.GetPosition() != tilePos ) { // If this isn't the goal tile, close it. tile->Close( searchIndex ); for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i ) { // Determine the direction to search. PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ]; // If the adjacent tile isn't in the previous direction, get the adjacent tile. Iterator adjacent = tile.GetAdjacent( direction ); if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) ) { // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile. TerrainType* adjacentTerrainType = adjacent->GetTerrainType(); if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) ) { // If the adjacent tile is passable, find the total cost of entering the tile. int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType ); int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent ); int distanceToGoal = ( originTile.GetPosition().GetManhattanDistanceTo( tilePos ) ); int adjacentWeight = ( adjacentTotalCost + distanceToGoal ); if( adjacentTotalCost <= movementRange ) { if( !adjacent->IsOpen( searchIndex ) ) { // If the tile info isn't already on the open list, add it. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.insert( adjacentWeight, adjacent ); } else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() ) { // If the node is already on the open list but has a larger total cost, // update the value. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.update( adjacentWeight, adjacent ); } } } } } } else { // If this is the goal tile, construct the path to the location. PrimaryDirection previousDirection = tile->GetPreviousTileDirection(); while( previousDirection != PrimaryDirection::NONE ) { // Construct the list of directions from the goal back to the origin tile. reverseDirections.push_back( previousDirection ); tile = tile.GetAdjacent( previousDirection ); previousDirection = tile->GetPreviousTileDirection(); } // End the search. break; } } for( auto it = reverseDirections.rbegin(); it != reverseDirections.rend(); ++it ) { // Construct the path by reversing the directions from the goal to the origin. PrimaryDirection direction = *it; result.AddDirection( direction.GetOppositeDirection() ); } }
void Map::FindReachableTiles( const Unit* unit, TileSet& result ) { int searchIndex = ReserveSearchIndex(); // Clear the list of results. result.clear(); // Clear the open list. mOpenList.clear(); // Get the Unit's current Tile and type. Iterator originTile = unit->GetTile(); UnitType* unitType = unit->GetUnitType(); MovementType* movementType = unit->GetMovementType(); // Get the starting movement range of the Unit. int movementRange = unit->GetMovementRange(); // Add the origin tile to the open list. originTile->Open( searchIndex ); originTile->SetPreviousTileDirection( PrimaryDirection::NONE ); originTile->SetBestTotalCostToEnter( 0 ); mOpenList.insert( 0, originTile ); while( !mOpenList.isEmpty() ) { // Pop the first element off the open list. Map::Iterator tile = mOpenList.popMinElement(); // Close the tile and add it to the result. tile->Close( searchIndex ); result.insert( tile ); for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i ) { // Determine the direction to search. PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ]; // If the adjacent tile isn't in the previous direction, get the adjacent tile. Iterator adjacent = tile.GetAdjacent( direction ); if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) ) { // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile. TerrainType* adjacentTerrainType = adjacent->GetTerrainType(); if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) ) { // If the adjacent tile is passable, find the total cost of entering the tile. int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType ); int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent ); if( adjacentTotalCost <= movementRange ) { if( !adjacent->IsOpen( searchIndex ) ) { // If the tile info isn't already on the open list, add it. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.insert( adjacentTotalCost, adjacent ); } else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() ) { // If the node is already on the open list but has a larger total cost, // update the value. adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() ); adjacent->SetBestTotalCostToEnter( adjacentTotalCost ); mOpenList.update( adjacentTotalCost, adjacent ); } } } } } } }