Unit* PlaceToolInputState::CreateUnitAtScreenCoords( const Vec2f& screenCoords )
{
	Unit* unit = nullptr;

	if( mSelectedUnitType )
	{
		if( mSelectedFaction )
		{
			EditorState* owner = GetOwnerDerived();
			MapView* mapView = owner->GetMapView();
			Map* map = owner->GetMap();

			// Get the Tile at the screen coords.
			Vec2f worldPos = mapView->ScreenToWorldCoords( screenCoords );
			Vec2s tilePos = mapView->WorldToTileCoords( worldPos );
			Map::Iterator tile = map->GetTile( tilePos );

			if( tile.IsValid() && tile->IsEmpty() && mSelectedUnitType->CanMoveAcrossTerrain( tile->GetTerrainType() ) )
			{
				// If the selected UnitType can be placed into the Tile, create a new Unit.
				DebugPrintf( "Placing Unit at tile (%d,%d)!", tilePos.x, tilePos.y );
				unit = map->CreateUnit( mSelectedUnitType, mSelectedFaction, tilePos );
			}
			else
			{
				WarnFail( "Cannot place Unit into tile (%d,%d)!", tilePos.x, tilePos.y );
			}
		}
		else
		{
			WarnFail( "Cannot create Unit because no Faction was selected!" );
		}
	}
	else
	{
		WarnFail( "Cannot create Unit because no UnitType was selected!" );
	}

	return unit;
}
void UnitAttackAbility::DetermineAvailableActions( const Unit* unit, const Path& movementPath, Actions& result ) const
{
	// Get the UnitType of the Unit.
	UnitType* unitType = unit->GetUnitType();

	if( unitType->HasWeapons() )
	{
		// If this Unit has weapons, determine whether the Unit can wait in the destination square.
		Map* map = unit->GetMap();
		Map::Iterator destinationTile = map->GetTile( movementPath.GetDestination() );

		if( unit->CanOccupyTile( destinationTile ) )
		{
			// If the Unit can stop here, get the list of Units in attack range from this location.
			Map::Units unitsInRange;
			map->FindUnitsInRange( destinationTile.GetPosition(), unitType->GetAttackRange(), unitsInRange );

			for( auto it = unitsInRange.begin(); it != unitsInRange.end(); ++it )
			{
				Unit* target = *it;

				if( unit->CanAttack( target ) )
				{
					// Add an attack action to the list of actions.
					UnitAttackAbility::Action* attackAction = new UnitAttackAbility::Action();

					attackAction->UnitID = unit->GetID();
					attackAction->TargetID = target->GetID();
					attackAction->MovementPath = movementPath;

					result.push_back( attackAction );
				}
			}
		}
	}
}
Beispiel #3
0
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() );
    }
}
Beispiel #4
0
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 );
                        }
                    }
                }
            }
        }
    }
}