void CartSupplier::onDestination()
{
  Walker::onDestination();
  CityHelper helper( _d->city );
  
  if( _getPathway().isReverse() )
  {
    // walker is back in the market
    deleteLater();
    // put the content of the stock to receiver
    BuildingPtr building = helper.find<Building>( _d->baseBuildingPos );

    GoodStore* storage = 0;
    if( building.is<Factory>() )
    {
      storage = &building.as<Factory>()->getGoodStore();
    }
    else if( building.is<Granary>() )
    {
      storage = &building.as<Granary>()->getGoodStore();
    }
    else if( building.is<Warehouse>() )
    {
      storage = &building.as<Warehouse>()->getGoodStore();
    }

    if( storage )
    {
      storage->applyStorageReservation( _d->stock, _d->rcvReservationID );
      storage->store( _d->stock, _d->stock._currentQty );
    }
  }
  else
  {
    // walker is near the granary/warehouse
    _getPathway().rbegin();
    computeDirection();
    go();

    // get goods from destination building
    
    BuildingPtr building = helper.find<Building>( _d->storageBuildingPos );

    if( building.is<Granary>() )
    {
      GranaryPtr granary = building.as<Granary>();
      // this is a granary!
      // std::cout << "MarketBuyer arrives at granary, res=" << _reservationID << std::endl;
      granary->getGoodStore().applyRetrieveReservation( _d->stock, _d->reservationID );      
    }
    else if( building.is<Warehouse>() )
    {
      WarehousePtr warehouse = building.as<Warehouse>();
      // this is a warehouse!
      // std::cout << "Market buyer takes IRON from warehouse" << std::endl;
      // warehouse->retrieveGoods(_basket.getStock(G_IRON));
      warehouse->getGoodStore().applyRetrieveReservation(_d->stock, _d->reservationID);
    }
  }
}
void WalkerPrefect::_back2Prefecture()
{
  bool pathFound = Pathfinder::getInstance().getPath( getIJ(), getBase()->getTile().getIJ(),
                                                      _getPathway(), false, Size( 0 ) );

  if( !pathFound )
  {
    deleteLater();
    _d->action = Impl::doNothing;
  }
  else
  {
    _getPathway().begin();
  }

  _setGraphic( WG_PREFECT );
  _d->action = Impl::back2Prefecture;
}
void CartPusher::timeStep( const unsigned long time )
{
  if( (time % 22 == 1) && (_getPathway().getLength() < 2) )
  {
    computeWalkerDestination();
  }

  Walker::timeStep( time );
}
void MarketLady::computeWalkerDestination( MarketPtr market )
{
  _d->market = market;
  std::list<GoodType> priorityGoods = _d->market->getMostNeededGoods();

  _d->destBuildingPos = TilePos( -1, -1 );  // no destination yet

  if( priorityGoods.size() > 0 )
  {
     // we have something to buy!

     // get the list of buildings within reach
     PathWay pathWay;
     Propagator pathPropagator( _d->city );
     pathPropagator.init( _d->market.as<Construction>() );
     pathPropagator.propagate( _d->maxDistance);

     // try to find the most needed good
     for (std::list<GoodType>::iterator itGood = priorityGoods.begin(); itGood != priorityGoods.end(); ++itGood)
     {
        _d->priorityGood = *itGood;

        if( _d->priorityGood == G_WHEAT || _d->priorityGood == G_FISH 
            || _d->priorityGood == G_MEAT || _d->priorityGood == G_FRUIT 
            || _d->priorityGood == G_VEGETABLE)
        {
           // try get that good from a granary
           _d->destBuildingPos = getWalkerDestination2<Granary>( pathPropagator, B_GRANARY, _d->market,
                                                              _d->basket, _d->priorityGood, pathWay, _d->reservationID );
        }
        else
        {
           // try get that good from a warehouse
           _d->destBuildingPos = getWalkerDestination2<Warehouse>( pathPropagator, B_WAREHOUSE, _d->market, 
                                                                _d->basket, _d->priorityGood, pathWay, _d->reservationID );
        }

        if( _d->destBuildingPos.getI() >= 0 )
        {
           // we found a destination!
           setPathWay(pathWay);
           break;
        }
     }
  }

  if( _d->destBuildingPos.getI() < 0)
  {
     // we have nothing to buy, or cannot find what we need to buy
     deleteLater();
     return;
  }

  setIJ( _getPathway().getOrigin().getIJ() );
}
void CartPusher::onDestination()
{
  Walker::onDestination();
  _d->cartPicture = Picture();

  if( _d->consumerBuilding != NULL )
  {
    GranaryPtr granary = _d->consumerBuilding.as<Granary>();
    WarehousePtr warehouse = _d->consumerBuilding.as<Warehouse>();
    FactoryPtr factory = _d->consumerBuilding.as<Factory>(); 
    if( granary != NULL )
    {
       granary->getGoodStore().applyStorageReservation(_d->stock, _d->reservationID);
       _d->reservationID = 0;
    }
    else if ( warehouse != NULL )
    {
       warehouse->getGoodStore().applyStorageReservation(_d->stock, _d->reservationID);
       _d->reservationID = 0;
    }
    else if( factory != NULL )
    {
       factory->getGoodStore().applyStorageReservation(_d->stock, _d->reservationID);
       // factory->computePictures();
       _d->reservationID = 0;
    }
  }
  //
  if( !_getPathway().isReverse() )
  {
    _getPathway().toggleDirection();
    computeDirection();
    go();
    _d->consumerBuilding = 0;
  }
  else
  {
    deleteLater();
  }
}
void CartPusher::computeWalkerDestination()
{
   // get the list of buildings within reach
   PathWay pathWay;
   Propagator pathPropagator( _getCity() );
   _d->consumerBuilding = 0;

   if( _d->producerBuilding.isNull() )
   {
     StringHelper::debug( 0xff, "CartPusher destroyed: producerBuilding can't be NULL" );
     deleteLater();
     return;
   }

   pathPropagator.init( _d->producerBuilding.as<Construction>() );
   pathPropagator.propagate(_d->maxDistance);

   BuildingPtr destBuilding;
   if (destBuilding == NULL)
   {
      // try send that good to a factory
      destBuilding = _d->getWalkerDestination_factory(pathPropagator, pathWay);
   }

   if (destBuilding == NULL)
   {
      // try send that good to a granary
      destBuilding = _d->getWalkerDestination_granary(pathPropagator, pathWay);
   }

   if (destBuilding == NULL)
   {
      // try send that good to a warehouse
      destBuilding = _d->getWalkerDestination_warehouse( pathPropagator, pathWay );
   }

   if( destBuilding != NULL)
   {
      //_isDeleted = true;  // no destination!
     setConsumerBuilding( destBuilding );
     setPathWay( pathWay );
     setIJ( _getPathway().getOrigin().getIJ() );
     setSpeed( 1 );
   }
   else
   {
     _setDirection( D_NORTH );
     setSpeed( 0 );
     setIJ( _d->producerBuilding->getAccessRoads().front()->getIJ() );
     walk();
   }
}
void CartSupplier::computeWalkerDestination(BuildingPtr building, const Good::Type type, const int qty )
{
  _d->baseBuildingPos = building->getTilePos();
  _d->storageBuildingPos = TilePos( -1, -1 );  // no destination yet

  // we have something to buy!
  // get the list of buildings within reach
  PathWay pathWay;
  Propagator pathPropagator( _d->city );
  pathPropagator.init( building.as<Construction>() );
  pathPropagator.propagate( _d->maxDistance);

  // try get that good from a granary
  _d->storageBuildingPos = getSupplierDestination2<Granary>( pathPropagator, B_GRANARY,
                                                             type, qty, pathWay, _d->reservationID );

  if( _d->storageBuildingPos.getI() < 0 )
  {
    // try get that good from a warehouse
    _d->storageBuildingPos = getSupplierDestination2<Warehouse>( pathPropagator, B_WAREHOUSE,
                                                                 type, qty, pathWay, _d->reservationID );
  }

  if( _d->storageBuildingPos.getI() >= 0 )
  {
    // we found a destination!
    setPathWay(pathWay);    
  }
  else
  {
    // we have nothing to buy, or cannot find what we need to buy
    deleteLater();
    return;
  }

  setIJ( _getPathway().getOrigin().getIJ() );
}
void WalkerPrefect::onMidTile()
{
  ReachedBuildings reachedBuildings;
  TilePos firePos;
  bool haveBurningRuinsNear = _looks4Fire( reachedBuildings, firePos );  
  bool isDestination = _getPathway().isDestination();

  switch( _d->action )
  {
  case Impl::doNothing:
  break;

  case Impl::patrol:
  {
    if( haveBurningRuinsNear )
    {
      //tell our prefecture that need send prefect with water to fight with fire
      //on next deliverService

      //found fire, no water, go prefecture
      getBase().as<Prefecture>()->fireDetect( firePos );
      _back2Prefecture();

      Walker::onNewDirection();
    }
    else
    {
      foreach( BuildingPtr building, reachedBuildings )
      {
        building->applyService( ServiceWalkerPtr( this ) );

        HousePtr house = building.as<House>();
        if( house.isValid() && house->getHealthLevel() < 1 )
        {
          house->deleteLater();

          GameEventMgr::append( DisasterEvent::create( house->getTilePos(), DisasterEvent::plague ) );
        }
      }
    }

    if( isDestination )
    {
      _back2Prefecture();
    }

    Walker::onMidTile();
  }
  break;

  case Impl::back2Prefecture:
  {
    if( haveBurningRuinsNear )
    {
      //tell our prefecture that need send prefect with water to fight with fire
      //on next deliverService
      getBase().as<Prefecture>()->fireDetect( firePos );
    }

    if( isDestination )
    {
      deleteLater();
      _d->action = Impl::doNothing;
    }

    Walker::onMidTile();
  }
  break;

  case Impl::gotoFire:
  {
    if( _getPathway().getDestination().getIJ().distanceFrom( getIJ() ) < 1.5f )
    {
      LandOverlayPtr overlay = _getPathway().getDestination().getOverlay();
      if( overlay.isValid() && overlay->getType() == B_BURNING_RUINS )
      {
        _d->action = Impl::fightFire;
        _setGraphic( WG_PREFECT_FIGHTS_FIRE );
        Walker::onNewDirection();
        isDestination = false;
      }
    }

    if( isDestination )
    {
      if( !haveBurningRuinsNear || _d->water == 0 )
      {
        _back2Prefecture();
      }
      else
      {
        _setGraphic( WG_PREFECT_DRAG_WATER );
        _d->action = Impl::gotoFire;

        _checkPath2NearestFire( reachedBuildings );
        Walker::onNewDirection();
      }
    }

    Walker::onMidTile();
  }
  break;

  case Impl::fightFire:
  break;
  }
void MarketLady::onDestination()
{
   Walker::onDestination();
   if( _getPathway().isReverse() )
   {
      // walker is back in the market
      deleteLater();
      // put the content of the basket in the market
      _d->market->getGoodStore().storeAll( _d->basket );
   }
   else
   {
      // walker is near the granary/warehouse
      _getPathway().rbegin();
      _setAction( WA_MOVE );
      computeDirection();

      // get goods from destination building
      LandOverlayPtr building = _d->city->getTilemap().at( _d->destBuildingPos ).getTerrain().getOverlay();
      
      if( building.is<Granary>() )
      {
        GranaryPtr granary = building.as<Granary>();
        // this is a granary!
        // std::cout << "MarketLady arrives at granary, res=" << _reservationID << std::endl;
        granary->getGoodStore().applyRetrieveReservation(_d->basket, _d->reservationID);

        // take other goods if possible
        for (int n = 1; n<G_MAX; ++n)
        {
           // for all types of good (except G_NONE)
           GoodType goodType = (GoodType) n;
           int qty = _d->market->getGoodDemand(goodType) - _d->basket.getCurrentQty(goodType);
           if (qty != 0)
           {
              qty = std::min(qty, granary->getGoodStore().getMaxRetrieve(goodType));
              qty = std::min(qty, _d->basket.getMaxQty(_d->priorityGood) - _d->basket.getCurrentQty(_d->priorityGood));
              if (qty != 0)
              {
                 // std::cout << "extra retrieve qty=" << qty << " basket=" << _basket.getStock(goodType)._currentQty << std::endl;
                 GoodStock& stock = _d->basket.getStock(goodType);
                 granary->getGoodStore().retrieve(stock, qty);
              }
           }
        }
      }
      else if( building.is<Warehouse>() )
      {
        WarehousePtr warehouse = building.as<Warehouse>();
        // this is a warehouse!
        // std::cout << "Market buyer takes IRON from warehouse" << std::endl;
        // warehouse->retrieveGoods(_basket.getStock(G_IRON));
        warehouse->getGoodStore().applyRetrieveReservation(_d->basket, _d->reservationID);

        // take other goods if possible
        for (int n = 1; n<G_MAX; ++n)
        {
           // for all types of good (except G_NONE)
           GoodType goodType = (GoodType) n;
           int qty = _d->market->getGoodDemand(goodType) - _d->basket.getCurrentQty(goodType);
           if (qty != 0)
           {
              qty = std::min(qty, warehouse->getGoodStore().getMaxRetrieve(goodType));
              qty = std::min(qty, _d->basket.getMaxQty(_d->priorityGood) - _d->basket.getCurrentQty(_d->priorityGood));
              if (qty != 0)
              {
                 // std::cout << "extra retrieve qty=" << qty << " basket=" << _basket.getStock(goodType)._currentQty << std::endl;
                 GoodStock& stock = _d->basket.getStock(goodType);
                 warehouse->getGoodStore().retrieve(stock, qty);
              }
           }
        }
      }

      unsigned long delay = 20;

      while( _d->basket.getCurrentQty() > 100 )
      {
        for( int gtype=G_WHEAT; gtype <= G_WINE; gtype++ )
        {
          GoodStock& currentStock = _d->basket.getStock( (GoodType)gtype );
          if( currentStock._currentQty > 0 )
          {
            MarketLadyHelperPtr boy = MarketLadyHelper::create( this );
            GoodStock& boyBasket =  boy->getBasket();
            boyBasket._goodType = (GoodType)gtype;
            boyBasket._maxQty = 100;
            _d->basket.retrieve( boyBasket, math::clamp( currentStock._currentQty, 0, 100 ) );
            boy->setDelay( delay );
            delay += 20;
            boy->send2City( _d->city, _d->market );
          }
        }
      }
   }
}