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(); } }
void WalkerDebugInfo::showPath( WalkerPtr walker, gfx::Engine& engine, gfx::Camera* camera ) { Point camOffset = camera->offset(); const Pathway& pathway = walker->pathway(); const TilesArray& tiles = pathway.allTiles(); Point pos = walker->mappos(); if( pathway.isReverse() ) { int rStart = pathway.length() - pathway.curStep(); for( int step=rStart-1; step >= 0; step-- ) { engine.drawLine( 0xff0000ff, pos + camOffset, tiles[ step ]->mappos() + camOffset + Point( 30, 0 ) ); pos = tiles[ step ]->mappos() + Point( 30, 0 ); } } else { for( unsigned int step=pathway.curStep()+1; step < tiles.size(); step++ ) { Tile* tile = tiles[ step ]; engine.drawLine( 0xff00ff00, pos + camOffset, tile->mappos() + camOffset + Point( 30, 0 ) ); pos = tile->mappos() + Point( 30, tile->height() * 15 ); } } }
void PlayerArmy::_reachedWay() { if( _d->mode == PlayerArmy::go2location ) { _attackAny(); return2fort(); } else if( _d->mode == PlayerArmy::go2home ) { PlayerCityPtr pCity = ptr_cast<PlayerCity>( _d->base ); if( pCity.isValid() ) { for( auto sldr : _d->soldiersInfo ) { int type = sldr.save[ "type" ]; WalkerPtr walker = WalkerManager::instance().create( (walker::Type)type, pCity ); walker->load( sldr.save ); walker->attach(); } auto fort = pCity->getOverlay( _d->fortPos ).as<Fort>(); if( fort.isValid() ) { fort->returnSoldiers(); fort->resetExpedition(); } } deleteLater(); } }
void SeaMerchant::Impl::resolveState(PlayerCityPtr city, WalkerPtr wlk ) { switch( nextState ) { case stFindDock: { destBuildingPos = TilePos( -1, -1 ); // no destination yet Pathway pathway; // get the list of buildings within reach if( tryDockCount < maxTryDockCount ) { city::Helper helper( city ); DockList docks = helper.find<Dock>( objects::dock ); if( !docks.empty() ) { DockList freeDocks; foreach( dock, docks ) { if( !(*dock)->isBusy() ) { freeDocks.push_back( *dock ); } } if( freeDocks.empty() ) { pathway = findRandomRaid( docks, wlk->pos() ); nextState = stWaitFreeDock; } else { pathway = findNearbyDock( freeDocks, wlk->pos() ); nextState = stRequestGoods; } } } tryDockCount++; if( pathway.isValid() ) { // we found a destination! wlk->setPathway( pathway ); wlk->go(); } else { nextState = stGoOutFromCity; resolveState( city, wlk ); } }
bool RomeSoldier::die() { bool created = Soldier::die(); if( !created ) { WalkerPtr w = Corpse::create(_city(), this ); Logger::warningIf( w.isNull(), "RomeSoldier: cannot create corpse for type " + WalkerHelper::getTypename( type() ) ); return w.isValid(); } return created; }
void RomeSoldier::timeStep(const unsigned long time) { Soldier::timeStep( time ); if( game::Date::isMonthChanged() ) { unsigned int dst2base = pos().distanceFrom( _d->basePos ); if( dst2base > maxDistanceFromBase ) { updateMorale( dst2base * -10 / maxDistanceFromBase ); if( morale() == 0 ) { _duckout(); } } } switch( _subAction() ) { case fightEnemy: { WalkerList enemies = _findEnemiesInRange( attackDistance() ); if( !enemies.empty() ) { WalkerPtr p = enemies.front(); turn( p->pos() ); p->updateHealth( -3 ); p->acceptAction( Walker::acFight, pos() ); } else { bool haveEnemy = _tryAttack(); if( !haveEnemy ) send2patrol(); } } break; case patrol: if( game::Date::current().day() % 2 == 0 ) { _tryAttack(); } break; default: break; } // end switch( _d->action ) }
bool Soldier::isFriendTo(WalkerPtr wlk) const { bool isFriend = _dfunc()->friends.count( wlk->type() ) > 0; if( !isFriend ) { isFriend = WalkerRelations::isNeutral( type(), wlk->type() ); if( nation() != world::unknownNation ) { isFriend = WalkerRelations::isNeutral( nation(), wlk->nation() ); } } return isFriend; }
void WorkingBuilding::addWalker( WalkerPtr walker ) { if( walker.isValid() ) { _d->walkerList.push_back( walker ); } }
void Wolf::_centerTile() { Animal::_centerTile(); WalkerList walkers = _city()->statistic().walkers .neighbors<Walker>( pos() ) .exclude<Wolf>(); if( !walkers.empty() ) { WalkerPtr wlk = walkers.random(); turn( wlk->pos() ); _setAction( acFight ); //setSpeedMultiplier( 0.0 ); _d->attackPos = wlk->pos(); } }
void WalkerDebugInfo::showPath( WalkerPtr walker, gfx::Engine& engine, gfx::Camera* camera, NColor color ) { Point camOffset = camera->offset(); const Pathway& pathway = walker->pathway(); const TilesArray& tiles = pathway.allTiles(); NColor pathColor = color; if( color == 0) { if( walker->agressive() > 0 ) { pathColor = DefaultColors::red; } else { pathColor = pathway.isReverse() ? DefaultColors::blue : DefaultColors::green; } } Point pos = walker->mappos(); Point xOffset( tilemap::cellSize().width(), 0 ); PointsArray points; if( pathway.isReverse() ) { int rStart = pathway.length() - pathway.curStep(); for( int step=rStart-1; step >= 0; step-- ) { pos = tiles[ step ]->mappos() + camOffset + xOffset; points.push_back( pos ); } } else { for( unsigned int step=pathway.curStep()+1; step < tiles.size(); step++ ) { pos = tiles[ step ]->mappos() + camOffset + xOffset; points.push_back( pos ); } } engine.drawLines( pathColor, points ); }
std::string WalkerThinks::check(WalkerPtr walker, PlayerCityPtr city, const StringArray& own) { city::InfoPtr info = city->statistic().services.find<Info>(); if( info.isNull() ) { Logger::warning( "CitizenIdea::check no city service info" ); return "##unknown_reason##"; } if( walker.is<Animal>() ) { std::string text = fmt::format( "##animal_{}_say##", walker->info().typeName() ); return text; } Info::Parameters params = info->lastParams(); ThinksConstructor ret( walker->info().typeName() ); ret.append(own); ret.addIf( params[ Info::monthWithFood ] < 3, "_so_hungry" ) .addIf( params[ Info::godsMood ] < 3, "_gods_angry" ) .addIf( params[ Info::colosseumCoverage ] < 3, "_need_colosseum" ) .addIf( params[ Info::theaterCoverage ] < 3, "_need_theater" ) .addIf( params[ Info::entertainment ] < 20, "_low_entertainment" ) .addIf( params[ Info::needWorkers ] > 0, "_need_workers" ) .addIf( params[ Info::workless ] > 15, "_high_workless" ) .addIf( params[ Info::tax ] > 10, "_high_tax" ) .addIf( params[ Info::payDiff ] < 0, "_low_salary" ); if( !ret.empty() ) return ret.random(); ret.clear(); ret.append(own); ret.addIf( params[ Info::lifeValue ] > 90, "_good_life" ) .addIf( params[ Info::lifeValue ] > 75, "_average_life" ) .addIf( params[ Info::lifeValue ] > 50, "_normal_life" ) .addIf( params[ Info::education ] > 90, "_good_education" ); return ret.empty() ? "##unknown_reason##" : ret.random(); }
inline bool Statistic::_Map::isTileBusy( const TilePos& p, WalkerPtr caller, bool& needMeMove ) const { needMeMove = false; auto walkers = _parent.rcity.walkers( p ).select<T>(); if( !walkers.empty() ) { needMeMove = (caller.object() != walkers.front().object()); } return walkers.size() > 1; }
void Walkers::update(PlayerCityPtr, unsigned int time) { WalkerList::iterator it = begin(); while( it != end() ) { WalkerPtr walker = *it; walker->timeStep( time ); if( walker->isDeleted() ) { // remove the walker from the walkers list //grid.remove( *it ); it = erase(it); } else { ++it; } } merge(); grid.update( *this ); grid.sort(); }
void Peace::addCriminal( WalkerPtr wlk ) { if( is_kind_of<Rioter>( wlk ) ) { _d->rioterSeen = true; } /*else if( is_kind_of<Protestor>( wlk ) ) { _d->protestorOrMugglerSeen = true; }*/ else { Logger::warning( "Peace:addCrimianl unknown walker %d", wlk->type() ); _d->someCriminalSeen = true; } }
void Walkers::postpone(WalkerPtr w) { ++idCount; w->setUniqueId( idCount ); FlowList::postpone( w ); }
void RomeArcher::timeStep(const unsigned long time) { Soldier::timeStep( time ); switch( _subAction() ) { case Soldier::fightEnemy: { WalkerList enemies = _findEnemiesInRange( attackDistance() ); if( !enemies.empty() ) { WalkerPtr p = enemies.front(); turn( p->pos() ); if( _animationRef().index() == (int)(_animationRef().frameCount()-1) ) { _fire( p->pos() ); _updateAnimation( time+1 ); } } else { //_check4attack(); send2patrol(); } } break; case Soldier::destroyBuilding: { ConstructionList constructions = _findContructionsInRange( attackDistance() ); if( !constructions.empty() ) { ConstructionPtr b = constructions.front(); turn( b->pos() ); if( _animationRef().index() == (int)(_animationRef().frameCount()-1) ) { _fire( b->pos() ); _updateAnimation( time+1 ); } } else { //_check4attack(); send2patrol(); } } case Soldier::patrol: if( game::Date::current().day() % 2 == 0 ) { _tryAttack(); } break; default: break; } // end switch( _d->action ) }
void Merchant::Impl::resolveState( WalkerPtr wlk, const TilePos& position ) { switch( nextState ) { case stFindWarehouseForSelling: { destBuildingPos = TilePos( -1, -1 ); // no destination yet // get the list of buildings within reach Propagator pathPropagator( city ); Tilemap& tmap = city->getTilemap(); pathPropagator.init( tmap.at( position ) ); pathPropagator.propagate( maxDistance ); Propagator::DirectRoute route; //try found any available warehouse for selling our goods const GoodStore& buyOrders = city->getBuys(); if( buyOrders.getMaxQty() > 0 ) { route = getWarehouse4Sells( pathPropagator, sell ); } if( !route.first.isValid() ) { route = pathPropagator.getShortestRoute( building::warehouse ); } if( route.first.isValid() ) { // we found a destination! nextState = stSellGoods; destBuildingPos = route.first->getTilePos(); wlk->setPathway( route.second ); wlk->setIJ( route.second.getOrigin().getIJ() ); wlk->go(); } else { nextState = stGoOutFromCity; resolveState( wlk, position ); } } break; case stFindWarehouseForBuying: { destBuildingPos = TilePos( -1, -1 ); // no destination yet // get the list of buildings within reach Propagator pathPropagator( city ); Tilemap& tmap = city->getTilemap(); pathPropagator.init( tmap.at( position ) ); pathPropagator.propagate( maxDistance ); Propagator::DirectRoute route; // try to find goods for city export if( buy.getMaxQty() > 0 ) { route = getWarehouse4Buys( pathPropagator, buy ); } if( route.first.isValid() ) { // we found a destination! nextState = stBuyGoods; destBuildingPos = route.first->getTilePos(); wlk->setPathway( route.second ); wlk->setIJ( route.second.getOrigin().getIJ() ); wlk->go(); } else { nextState = stGoOutFromCity; resolveState( wlk, position ); } } break; case stBuyGoods: { CityHelper helper( city ); WarehousePtr warehouse = helper.find<Warehouse>( building::warehouse, destBuildingPos ); if( warehouse.isValid() ) { std::map< Good::Type, int > cityGoodsAvailable; WarehouseList warehouses = helper.find<Warehouse>( building::warehouse ); foreach( WarehousePtr wh, warehouses ) { for( int i=Good::wheat; i < Good::goodCount; i++ ) { Good::Type goodType = (Good::Type)i; cityGoodsAvailable[ goodType ] += wh->getGoodStore().getCurrentQty( goodType ); } } //const GoodStore& cityOrders = city->getSells(); CityTradeOptions& options = city->getTradeOptions(); //try buy goods for( int n = Good::wheat; n<Good::goodCount; ++n ) { Good::Type goodType = (Good::Type) n; int needQty = buy.getFreeQty( goodType ); int maySell = math::clamp( cityGoodsAvailable[ goodType ] - options.getExportLimit( goodType ) * 100, 0, 9999 ); if( needQty > 0 && maySell > 0) { int mayBuy = std::min( needQty, warehouse->getGoodStore().getMaxRetrieve( goodType ) ); mayBuy = std::min( mayBuy, maySell ); if( mayBuy > 0 ) { // std::cout << "extra retrieve qty=" << qty << " basket=" << _basket.getStock(goodType)._currentQty << std::endl; GoodStock& stock = buy.getStock( goodType ); warehouse->getGoodStore().retrieve( stock, mayBuy ); events::GameEventPtr e = events::FundIssueEvent::exportg( goodType, mayBuy ); e->dispatch(); } } } } nextState = stGoOutFromCity; resolveState( wlk, position ); } break; case stGoOutFromCity: { Pathway pathWay; // we have nothing to buy/sell with city, or cannot find available warehouse -> go out bool pathFound = Pathfinder::getInstance().getPath( position, city->getBorderInfo().roadExit, pathWay, false, 1 ); if( pathFound ) { wlk->setPathway( pathWay ); wlk->setIJ( pathWay.getOrigin().getIJ() ); wlk->go(); } else { wlk->deleteLater(); } nextState = stBackToBaseCity; } break; case stSellGoods: { CityHelper helper( city ); WarehousePtr warehouse = helper.find<Warehouse>( building::warehouse, destBuildingPos ); const GoodStore& cityOrders = city->getBuys(); if( warehouse.isValid() ) { //try sell goods for (int n = Good::wheat; n<Good::goodCount; ++n) { Good::Type goodType = (Good::Type)n; int qty4sell = sell.getCurrentQty( goodType ); if( qty4sell > 0 && cityOrders.getMaxQty( goodType ) > 0 ) { int maySells = std::min( qty4sell, warehouse->getGoodStore().getMaxStore( goodType ) ); if( maySells != 0 ) { // std::cout << "extra retrieve qty=" << qty << " basket=" << _basket.getStock(goodType)._currentQty << std::endl; GoodStock& stock = sell.getStock( goodType ); warehouse->getGoodStore().store( stock, maySells ); events::GameEventPtr e = events::FundIssueEvent::import( goodType, maySells ); e->dispatch(); } } } } nextState = stFindWarehouseForBuying; resolveState( wlk, position ); } break; case stBackToBaseCity: { // walker on exit from city wlk->deleteLater(); EmpirePtr empire = city->getEmpire(); const std::string& ourCityName = city->getName(); EmpireTradeRoutePtr route = empire->getTradeRoute( ourCityName, baseCityName ); if( route.isValid() ) { route->addMerchant( ourCityName, sell, buy ); } nextState = stNothing; } break; default: Logger::warning( "Merchant: unknown state resolved" ); }