コード例 #1
0
ファイル: prefecture.cpp プロジェクト: BlackFoks/opencaesar3
void Prefecture::deliverService()
{
  if( getWorkers() > 0 && getWalkerList().size() == 0 )
  {
    bool fireDetect = _fireDetect.getI() >= 0;
    PrefectPtr walker = Prefect::create( _getCity() );
    walker->setMaxDistance( 26 );

    //bool patrol = true;
    if( fireDetect )
    {
      Pathway pathway;
      TilePos startPos = getAccessRoads().front()->getIJ();
      bool pathFounded = Pathfinder::getInstance().getPath( startPos, _fireDetect, pathway, false, Size( 0 ) );
      //patrol = !pathFounded;

      if( pathFounded )
      {
        walker->setPathway( pathway );
        walker->setIJ( pathway.getOrigin().getIJ() );
      }

      _fireDetect = TilePos( -1, -1 );
    }
    
    walker->send2City( PrefecturePtr( this ), fireDetect ? 200 : 0 );

    addWalker( walker.as<Walker>() );
  }
}
コード例 #2
0
  Pathway findWay( const TilesArray& startTiles, const TilesArray& arrivedTiles )
  {
    if( arrivedTiles.empty() || startTiles.empty() )
      return Pathway();

    Pathfinder& pathfinder = Pathfinder::instance();
    unsigned int mainLimiter = 10;
    unsigned int stTileLimiter = startTiles.size() > mainLimiter
                                   ? startTiles.size() / mainLimiter : 1;
    for( unsigned int tileIndex = 0; tileIndex < startTiles.size(); tileIndex += stTileLimiter )
    {
      Tile* rtile = startTiles[ tileIndex ];

      unsigned int arvTileLimiter = arrivedTiles.size() > mainLimiter
                                      ? arrivedTiles.size() / mainLimiter : 1;
      for( unsigned int arvTileIndex=0; arvTileIndex < arrivedTiles.size(); arvTileIndex += arvTileLimiter )
      {
        Tile* endTile = arrivedTiles[ arvTileIndex ];

        Pathway way = pathfinder.getPath( *rtile, *endTile, Pathfinder::customCondition | Pathfinder::fourDirection );

        if( way.isValid() )
          return way;
      }
    }

    return Pathway();
  }
コード例 #3
0
ファイル: animals.cpp プロジェクト: dalerank/caesaria-game
void Wolf::_findNewWay( const TilePos& start )
{  
  WalkerList walkers = _city()->statistic().walkers
                                           .find<Walker>( walker::any, config::distance::animalRandrom, start )
                                           .exclude<Wolf>();

  Pathway pathway;
  if( !walkers.empty() )
  {
    WalkerPtr wlk = walkers.random();
    pathway = PathwayHelper::create( start, wlk->pos(), PathwayHelper::allTerrain );
  }

  if( !pathway.isValid() )
  {
    pathway = PathwayHelper::randomWay( _city(), start, config::distance::animalRandrom );
  }

  if( pathway.isValid() )
  {
    setPos( start );
    setPathway( pathway );
    go();
  }
  else
  {
    die();
  }
}
コード例 #4
0
inline Pathway Statistic::_Walkers::freeTile( TilePos target, TilePos currentPos, const int range ) const
{
  for( int currentRange=1; currentRange <= range; currentRange++ )
  {
    TilePos offset( currentRange, currentRange );
    gfx::TilesArray tiles = _parent.map.perimetr( currentPos - offset, currentPos + offset );
    tiles = tiles.walkables( true );

    float crntDistance = target.distanceFrom( currentPos );
    for( auto tile : tiles )
    {
      SmartList<T> eslist = _parent.rcity.walkers( tile->pos() ).select<T>();

      if( !eslist.empty() )
        continue;

      if( target.distanceFrom( tile->pos() ) > crntDistance )
        continue;

      Pathway pathway = PathwayHelper::create( currentPos, tile->pos(), PathwayHelper::allTerrain );
      if( pathway.isValid() )
      {
        return pathway;
      }
    }
  }

  return Pathway();
}
コード例 #5
0
ファイル: emigrant.cpp プロジェクト: mdl8bit/caesaria-game
Pathway Emigrant::_findSomeWay( TilePos startPoint )
{
  HousePtr house = _findBlankHouse();  
  _d->failedWayCount++;

  Pathway pathway;
  if( house.isValid() )
  {    
    pathway = PathwayHelper::create( startPoint, house->pos(), PathwayHelper::roadFirst  );

    if( !pathway.isValid() )
    {
      pathway = PathwayHelper::create( startPoint, ptr_cast<Construction>(house),
                                       PathwayHelper::roadFirst  );
    }

    if( pathway.isValid() )
    {
      _lockHouse( house );
    }
  }

  if( !pathway.isValid() || _d->failedWayCount > 10 )
  {    
    pathway = PathwayHelper::create( startPoint,
                                     _city()->borderInfo().roadExit,
                                     PathwayHelper::allTerrain );
  }

  return pathway;
}
コード例 #6
0
float3
OpenSteer::SteerLibrary::
steerToFollowPath (const AbstractVehicle& v, 
				   const int direction,
                   const float predictionTime,
                   Pathway& path)
{
    // our goal will be offset from our path distance by this amount
    const float pathDistanceOffset = direction * predictionTime * v.speed();

    // predict our future position
    const float3 futurePosition = v.predictFuturePosition (predictionTime);

    // measure distance along path of our current and predicted positions
    const float nowPathDistance =
        path.mapPointToPathDistance (make_float3(v.position ()));
    const float futurePathDistance =
        path.mapPointToPathDistance (futurePosition);

    // are we facing in the correction direction?
    const bool rightway = ((pathDistanceOffset > 0) ?
                           (nowPathDistance < futurePathDistance) :
                           (nowPathDistance > futurePathDistance));

    // find the point on the path nearest the predicted future position
    // XXX need to improve calling sequence, maybe change to return a
    // XXX special path-defined object which includes two float3s and a 
    // XXX bool (onPath,tangent (ignored), withinPath)
    float3 tangent;
    float outside;
    const float3 onPath = path.mapPointToPath (futurePosition,
                                             // output arguments:
                                             tangent,
                                             outside);

    // no steering is required if (a) our future position is inside
    // the path tube and (b) we are facing in the correct direction
    if ((outside < 0) && rightway)
    {
        // all is well, return zero steering
        return float3_zero();
    }
    else
    {
        // otherwise we need to steer towards a target point obtained
        // by adding pathDistanceOffset to our current path position

        float targetPathDistance = nowPathDistance + pathDistanceOffset;
        float3 target = path.mapPathDistanceToPoint (targetPathDistance);

        annotatePathFollowing (futurePosition, onPath, target, outside);

        // return steering to seek target on path
        return steerForSeek (v, target);
    }
}
コード例 #7
0
ファイル: pathway.cpp プロジェクト: andrelago13/caesaria-game
bool operator<(const Pathway& v1, const Pathway& v2)
{
    if( v1.length()!=v2.length() )
    {
        return v1.length() < v2.length();
    }

    // compare memory address
    return (&v1 < &v2);
}
コード例 #8
0
ファイル: romesoldier.cpp プロジェクト: binakot/caesaria-game
void RomeSoldier::send2expedition(const std::string& name)
{
  _d->expedition = name;
  TilePos cityEnter = _city()->borderInfo().roadEntry;

  Pathway way = PathwayHelper::create( pos(), cityEnter, PathwayHelper::allTerrain );
  if( way.isValid() )
  {
    setPathway( way );
    _setSubAction( (SldrAction)expedition );
    go();
  }
}
コード例 #9
0
ファイル: emigrant.cpp プロジェクト: mdl8bit/caesaria-game
void Emigrant::_reachedPathway()
{
  bool gooutCity = true;
  Walker::_reachedPathway();

  if( pos() == _city()->borderInfo().roadExit )
  {
    city::MigrationPtr migration;
    migration << _city()->findService( city::Migration::defaultName() );

    if( migration.isValid() )
    {
      migration->citizenLeaveCity( this );
    }

    deleteLater();
    return;
  }

  HousePtr house = ptr_cast<House>( _city()->getOverlay( pos() ) );
  if( house.isValid() )
  {
    _append2house( house );
    gooutCity = (_d->peoples.count() > 0);
  }
  else
  {
    if( _checkNearestHouse() )
    {
      return;
    }
  }

  if( gooutCity )
  {
    Pathway way = _findSomeWay( pos() );
    if( way.isValid() )
    {
      _updatePathway( way );
      go();
    }
    else
    {
      die();
    }
  }
  else
  {
    deleteLater();
  }
}
コード例 #10
0
ファイル: patrician.cpp プロジェクト: BlackFoks/opencaesar3
void Patrician::_findNewWay( const TilePos& start )
{
  Pathway pathway = PathwayHelper::randomWay( _getCity(), start, 10 );

  if( pathway.isValid() )
  {
    setPathway( pathway );
    setIJ( start );
    go();
  }
  else
  {
    die();
  }
}
コード例 #11
0
ファイル: animals.cpp プロジェクト: dalerank/caesaria-game
void Animal::_findNewWay( const TilePos& start )
{
  Pathway pathway = PathwayHelper::randomWay( _city(), start, config::distance::animalRandrom );

  if( pathway.isValid() )
  {
    setPos( start );
    setPathway( pathway );
    go();
  }
  else
  {
    die();
  }
}
コード例 #12
0
float3
OpenSteer::SteerLibrary::
steerToStayOnPath (const AbstractVehicle& v, 
				   const float predictionTime, 
				   Pathway& path)
{
    // predict our future position
    const float3 futurePosition = v.predictFuturePosition (predictionTime);

    // find the point on the path nearest the predicted future position
    float3 tangent;
    float outside;
    const float3 onPath = path.mapPointToPath (futurePosition,
                                             tangent,     // output argument
                                             outside);    // output argument

    if (outside < 0)
    {
        // our predicted future position was in the path,
        // return zero steering.
        return float3_zero();
    }
    else
    {
        // our predicted future position was outside the path, need to
        // steer towards it.  Use onPath projection of futurePosition
        // as seek target
        annotatePathFollowing (futurePosition, onPath, onPath, outside);
        return steerForSeek (v, onPath);
    }
}
コード例 #13
0
ファイル: cart_pusher.cpp プロジェクト: binakot/caesaria-game
void CartPusher::_brokePathway(TilePos pos)
{
    _d->brokePathCounter++;
    if( _pathway().isValid() && _d->brokePathCounter < 5 )
    {
        Pathway way = PathwayHelper::create( pos, _pathway().stopPos(), PathwayHelper::roadFirst );
        if( way.isValid() )
        {
            setPathway( way );
            go();
            return;
        }
    }

    Logger::warning( "CartPusher::_brokePathway not destination point [%d,%d]", pos.i(), pos.j() );
    deleteLater();
}
コード例 #14
0
Pathway EnemySoldier::_findPathway2NearestEnemy( unsigned int range )
{
  Pathway ret;

  WalkerList walkers = _findEnemiesInRange( range );

  for( auto wlk : walkers)
  {
    ret = PathwayHelper::create( pos(), wlk->pos(), PathwayHelper::allTerrain );
    if( ret.isValid() )
    {
      return ret;
    }
  }

  return Pathway();
}
コード例 #15
0
ファイル: pathway.cpp プロジェクト: andrelago13/caesaria-game
Pathway Pathway::copy(unsigned int start, int stop) const
{
    Pathway ret;
    if( start >= length() )
    {
        return ret;
    }

    ret.init( *_d->tiles[ start ] );
    stop = (stop == -1 ? _d->tiles.size() : stop );
    for( int i=start+1; i < stop; i++ )
    {
        ret.setNextTile( *_d->tiles[ i ] );
    }

    return ret;
}
コード例 #16
0
ファイル: EFMGenerator.cpp プロジェクト: aldenks/efm-gpu
void EFMGenerator::generateCombinations(ReversibleTreeNode* input, ReversibleTreeNode* output) {
   ReactionBitData comboLabel;
   rbdOr(comboLabel, input->getBitsUsed(), output->getBitsUsed());
   if (!isValidPathway(comboLabel)) {
      return;
   }
   if (input->isLeaf()) {
      if (output->isLeaf()) {
         if (bptInput.isSuperSet(comboLabel, input->getBitsUsed()) || bptOutput.isSuperSet(comboLabel, output->getBitsUsed()) || bptNonpart.isSuperSet(comboLabel)) {
            return;
         }
         int iStart = input->getStart(), iEnd = input->getEnd();
         int oStart = output->getStart(), oEnd = output->getEnd();
         Pathway *combo = ++pathways;
         Pathway *in;
         Pathway *out;
         for (int i = iStart; i < iEnd; i++) {
            for (int o = oStart; o < oEnd; o++) {
               in = input->getPathway(i);
               out = output->getPathway(o);
               combo->setParents(in, out);
               combinationsGenerated++;
               if (!(bptInput.isSuperSet(combo, in) || bptOutput.isSuperSet(combo, out) || bptNonpart.isSuperSet(combo))) {
                  combinationsStored++;
                  combo = ++pathways;
               }
            }
         }
         --pathways;
      } else {
         generateCombinations(input, output->getNode0());
         generateCombinations(input, output->getNode1());
      }
   } else {
      if (output->isLeaf()) {
         generateCombinations(input->getNode0(), output);
         generateCombinations(input->getNode1(), output);
      } else {
         generateCombinations(input->getNode0(), output->getNode0());
         generateCombinations(input->getNode0(), output->getNode1());
         generateCombinations(input->getNode1(), output->getNode0());
         generateCombinations(input->getNode1(), output->getNode1());
      }
   }
}
コード例 #17
0
Pathway ChastenerElephant::_findPathway2NearestConstruction( unsigned int range )
{
  Pathway ret;

  for( unsigned int tmpRange=1; tmpRange <= range; tmpRange++ )
  {
    ConstructionList constructions = _findContructionsInRange( tmpRange );

    foreach( it, constructions )
    {
      ConstructionPtr c = ptr_cast<Construction>( *it );
      ret = PathwayHelper::create( pos(), c->pos(), makeDelegate( _d.data(), &Impl::mayMove ) );
      if( ret.isValid() )
      {
        return ret;
      }
    }
  }
コード例 #18
0
void EnemySoldier::_check4attack()
{
  //try find any walkers in range
  Pathway pathway = _findPathway2NearestEnemy( 10 );

  if( !pathway.isValid() )
  {
    int size = _city()->tilemap().size();
    pathway = _findPathway2NearestConstruction( size/2 );
  }   

  if( !pathway.isValid() )
  {
    pathway = PathwayHelper::create( pos(), _city()->borderInfo().roadExit,
                                     PathwayHelper::allTerrain );
    setTarget( TilePos( -1, -1) );
  }

  if( !pathway.isValid() )
  {
    pathway = PathwayHelper::randomWay( _city(), pos(), 10 );
    setTarget( TilePos( -1, -1) );
    _failedWayCounter++;
  }

  if( _failedWayCounter > 4 )
  {
    pathway = Pathway();
  }

  if( pathway.isValid() )
  {
    _setSubAction( target().i() >= 0 ? go2enemy : go2position );
    _updatePathway( pathway );
    go();
  }
  else
  {
    //impossible state, but...
    Logger::warning( "EnemySoldier: can't find any path" );
    die();
  }
}
コード例 #19
0
ファイル: romesoldier.cpp プロジェクト: binakot/caesaria-game
void RomeSoldier::_duckout()
{
  Pathway way = PathwayHelper::way2border( _city(), pos() );
  if( !way.isValid() )
  {
    way = PathwayHelper::randomWay( _city(), pos(), maxDistanceFromBase );
  }

  if( way.isValid() )
  {
    _setSubAction( duckout );
    setPathway( way );
    go();
  }
  else
  {
    die();
  }
}
コード例 #20
0
ファイル: mugger.cpp プロジェクト: KSLcom/caesaria-game
void Mugger::timeStep(const unsigned long time)
{
  Walker::timeStep( time );

  switch( _d->state )
  {
  case Impl::searchHouse:
  {
    city::Helper helper( _city() );
    TilePos offset(10, 10);

    HouseList houses = helper.find<House>( objects::house, pos() - offset, pos() + offset );
    std::map< int, HouseList > houseEpxens;
    foreach( it, houses )
    {
      int money = (*it)->getServiceValue( Service::forum );
      houseEpxens[ money ] << *it;
    }

    for( std::map< int, HouseList >::reverse_iterator expHList = houseEpxens.rbegin();
         expHList != houseEpxens.rend(); ++expHList )
    {
      HouseList& hlist = expHList->second;

      foreach( hIt, hlist )
      {
        Pathway pathway = PathwayHelper::create( pos(), ptr_cast<Construction>( *hIt ), PathwayHelper::allTerrain );

        //find path to most expensive house, fire this!!!
        if( pathway.isValid() )
        {
          setPos( pathway.startPos() );
          setPathway( pathway );
          go();
          _d->state = Impl::go2destination;
          break;
        }
      }

      _d->state = Impl::go2anyplace;
    }
  }
コード例 #21
0
ファイル: romesoldier.cpp プロジェクト: binakot/caesaria-game
void RomeSoldier::_back2base()
{
  FortPtr b = base();
  if( b.isValid() )
  {
    Pathway way = PathwayHelper::create( pos(), b->freeSlot( this ), PathwayHelper::allTerrain );

    if( way.isValid() )
    {
      setPathway( way );
      _setSubAction( go2position );
      go();
      return;
    }
  }
  else
  {
    die();
  }
}
コード例 #22
0
ファイル: romesoldier.cpp プロジェクト: binakot/caesaria-game
Pathway RomeSoldier::_findPathway2NearestEnemy( unsigned int range )
{
  Pathway ret;

  for( unsigned int tmpRange=1; tmpRange <= range; tmpRange++ )
  {
    WalkerList walkers = _findEnemiesInRange( tmpRange );

    for( auto w : walkers)
    {
      ret = PathwayHelper::create( pos(), w->pos(), PathwayHelper::allTerrain );
      if( ret.isValid() )
      {
        return ret;
      }
    }
  }

  return Pathway();
}
コード例 #23
0
ファイル: PathwayLoader.cpp プロジェクト: dzw/kylin001v
KBOOL Kylin::PathwayLoader::Load( KCCHAR* pScene )
{
	Ogre::FileInfoListPtr resPtr = Ogre::ResourceGroupManager::getSingletonPtr()->findResourceFileInfo("General", pScene);
	Ogre::FileInfo fInfo = (*(resPtr->begin()));
	
	KSTR sName = StringUtils::replace(pScene,".xml","_pathway.xml");
	KSTR sPath = fInfo.archive->getName();
	sPath += "/" + sName;
	
	XmlStream kXml(sPath.data());
	if (!kXml.Open(XmlStream::Read))
		return false;

	KBOOL bScene = kXml.SetToFirstChild("pathway");
	while (bScene)
	{
		Pathway* pPathway = KNEW Pathway;

		KUINT id		= kXml.GetAttrInt("id");
		KBOOL bTurnback = kXml.GetAttrBool("turnback");

		KBOOL bPoint = kXml.SetToFirstChild("point");
		while (bPoint)
		{
			KFLOAT fX = kXml.GetAttrFloat("x");
			KFLOAT fZ = kXml.GetAttrFloat("z");
		
			pPathway->Add(KPoint3(fX,0,fZ));

			bPoint = kXml.SetToNextChild("point");
		}

		m_kPathwayMap.insert(std::pair<KUINT,Pathway*>(id,pPathway));

		bScene = kXml.SetToNextChild("pathway");
	}

	kXml.Close();

	return true;
}
コード例 #24
0
ファイル: layerwater.cpp プロジェクト: dalerank/caesaria-game
void Water::_updatePaths()
{
  auto reservoir = _d->overlay.selected.as<Reservoir>();
  if( reservoir.isValid() )
  {
    _d->ways.clear();
    PathwayCondition wayCondition;
    auto fountains = reservoir->aquifer().overlays<Fountain>();

    for( auto fountain : fountains )
    {
      Pathway pathway = PathwayHelper::create( reservoir->pos(), fountain->pos(),
                                               wayCondition.bySomething(), Pathway::fourDirection  );
      if( pathway.isValid() )
        _d->ways.push_back( { pathway.allTiles(), ColorList::red } );
    }
  }

  auto fountain = _d->overlay.underMouse.as<Fountain>();
  if( fountain.isValid() )
  {
    _d->ways.clear();

    PathwayCondition wayCondition;
    auto reservoirs = _map().rect( 10, fountain->pos() ).overlays<Reservoir>();

    for( auto reservoir : reservoirs )
    {
      Pathway pathway = PathwayHelper::create( reservoir->pos(), fountain->pos(), wayCondition.bySomething() );
      if( pathway.isValid() )
        _d->ways.push_back( { pathway.allTiles(), ColorList::blue } );
    }
  }
}
コード例 #25
0
Pathway ChastenerElephant::_findPathway2NearestConstruction( unsigned int range )
{
  Pathway ret;

  ElephantWayCondition condition;

  for( unsigned int tmpRange=1; tmpRange <= range; tmpRange++ )
  {
    ConstructionList constructions = _findContructionsInRange( tmpRange );

    for( auto construction : constructions )
    {
      ret = PathwayHelper::create( pos(), construction->pos(), condition.mayMove() );
      if( ret.isValid() )
      {
        return ret;
      }
    }
  }

  return Pathway();
}
コード例 #26
0
ファイル: wallguard.cpp プロジェクト: dalerank/caesaria-game
void WallGuard::_brokePathway(TilePos p)
{
  Soldier::_brokePathway( p );

  if( _d->patrolPosition.i() >= 0 )
  {
    Pathway way = PathwayHelper::create( pos(), _d->patrolPosition,
                                         PathwayHelper::allTerrain );

    if( way.isValid() )
    {
      setPathway( way );
      go();
    }
    else
    {
      _setSubAction( patrol );
      setPathway( Pathway() );
      wait( game::Date::days2ticks( DateTime::daysInWeek ) );
    }
  }
}
コード例 #27
0
ファイル: romesoldier.cpp プロジェクト: binakot/caesaria-game
void RomeSoldier::_brokePathway(TilePos p)
{
  Soldier::_brokePathway( p );

  if( gfx::tilemap::isValidLocation( _d->patrolPosition ) )
  {
    Pathway way = PathwayHelper::create( pos(), _d->patrolPosition,
                                         PathwayHelper::allTerrain );

    if( way.isValid() )
    {
      setPathway( way );
      go();
    }
    else
    {
      _setSubAction( patrol );
      _setAction( acNone );
      setPathway( Pathway() );
    }
  }
}
コード例 #28
0
ファイル: Pathway.cpp プロジェクト: thortiede/unipax
bool UniPAX::Pathway::merge(Pathway& object)
{
	{
		std::set<UniPAX::ModelPtr> tmp(getModelExtensions().begin(), getModelExtensions().end());
		for (std::vector<UniPAX::ModelPtr>::iterator it = object.getModelExtensions().begin(); it != object.getModelExtensions().end(); it++)
		{
			if (*it != 0)
			{
				tmp.insert(*it);
			}
		}
		getModelExtensions().assign(tmp.begin(), tmp.end());
	}
	{
		std::set<UniPAX::EntityPtr> tmp(getPathwayComponents().begin(), getPathwayComponents().end());
		for (std::vector<UniPAX::EntityPtr>::iterator it = object.getPathwayComponents().begin(); it != object.getPathwayComponents().end(); it++)
		{
			if (*it != 0)
			{
				tmp.insert(*it);
			}
		}
		getPathwayComponents().assign(tmp.begin(), tmp.end());
	}
	{
		std::set<UniPAX::PathwayStepPtr> tmp(getPathwayOrders().begin(), getPathwayOrders().end());
		for (std::vector<UniPAX::PathwayStepPtr>::iterator it = object.getPathwayOrders().begin(); it != object.getPathwayOrders().end(); it++)
		{
			if (*it != 0)
			{
				tmp.insert(*it);
			}
		}
		getPathwayOrders().assign(tmp.begin(), tmp.end());
	}
	if (organism != 0)
	{
		if (object.getOrganism() != 0)
		{
			if (organism->getUnipaxId() != object.getOrganism()->getUnipaxId())
			{
				std::cerr << "Error during merging: UniPAX::Pathway::organism not equal ..."
						<< organism->getUnipaxId() << " != " << object.getOrganism()->getUnipaxId() << std::endl;
				return false;
			}
		}
	}
	else
	{
		setOrganism(object.getOrganism());
	}

	return UniPAX::Entity::merge(object);
}
コード例 #29
0
ファイル: wallguard.cpp プロジェクト: dalerank/caesaria-game
void WallGuard::send2city( TowerPtr tower, Pathway pathway )
{
  setPos( pathway.startPos() );
  setBase( tower );

  setPathway( pathway );
  go();

  _setSubAction( go2position );

  if( !isDeleted() )
  {
    attach();
  }
}
コード例 #30
0
Pathway PathwayHelper::randomWay(CityPtr city, TilePos startPos, int walkRadius)
{
    int loopCounter = 0; //loop limiter
    do
    {
        const Tilemap& tmap = city->getTilemap();

        TilePos destPos( std::rand() % walkRadius - walkRadius / 2, std::rand() % walkRadius - walkRadius / 2 );
        destPos = (startPos+destPos).fit( TilePos( 0, 0 ), TilePos( tmap.getSize()-1, tmap.getSize()-1 ) );

        if( tmap.at( destPos ).isWalkable( true) )
        {
            Pathway pathway = create( city, startPos, destPos, PathwayHelper::allTerrain );

            if( pathway.isValid() )
            {
                return pathway;
            }
        }
    }
    while( ++loopCounter < 20 );

    return Pathway();
}