예제 #1
0
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance *t)
{
	ui64 ret = 0;
	int freeHeroSlots = GameConstants::ARMY_SIZE - h->stacksCount();
	std::vector<const CStackInstance *> toMove;
	for(auto const slot : t->Slots())
	{
		//can be merged woth another stack?
		SlotID dst = h->getSlotFor(slot.second->getCreatureID());
		if(h->hasStackAtSlot(dst))
			ret += t->getPower(slot.first);
		else
			toMove.push_back(slot.second);
	}
	boost::sort(toMove, [](const CStackInstance *lhs, const CStackInstance *rhs)
	{
		return lhs->getPower() < rhs->getPower();
	});
	for (auto & stack : boost::adaptors::reverse(toMove))
	{
		if(freeHeroSlots)
		{
			ret += stack->getPower();
			freeHeroSlots--;
		}
		else
			break;
	}
	return ret;
}
예제 #2
0
int3 whereToExplore(HeroPtr h)
{
	//TODO it's stupid and ineffective, write sth better
	cb->setSelection(*h);
	int radius = h->getSightRadious();
	int3 hpos = h->visitablePos();

	//look for nearby objs -> visit them if they're close enouh
	const int DIST_LIMIT = 3;
	std::vector<const CGObjectInstance *> nearbyVisitableObjs;
	for(const CGObjectInstance *obj : ai->getPossibleDestinations(h))
	{
		int3 op = obj->visitablePos();
		CGPath p;
		cb->getPath2(op, p);
		if(p.nodes.size() && p.endPos() == op && p.nodes.size() <= DIST_LIMIT)
			nearbyVisitableObjs.push_back(obj);
	}
	boost::sort(nearbyVisitableObjs, isCloser);
	if(nearbyVisitableObjs.size())
		return nearbyVisitableObjs.back()->visitablePos();

	try
	{
		return ai->explorationBestNeighbour(hpos, radius, h);
	}
	catch(cannotFulfillGoalException &e)
	{
		std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
		try
		{
			return ai->explorationNewPoint(radius, h, tiles);
		}
		catch(cannotFulfillGoalException &e)
		{
			std::map<int, std::vector<int3> > profits;
			{
				TimeCheck tc("Evaluating exploration possibilities");
				tiles[0].clear(); //we can't reach FoW anyway
				for(auto &vt : tiles)
					for(auto &tile : vt)
						profits[howManyTilesWillBeDiscovered(tile, radius)].push_back(tile);
			}

			if(profits.empty())
				return int3 (-1,-1,-1);

			auto bestDest = profits.end();
			bestDest--;
			return bestDest->second.front(); //TODO which is the real best tile?
		}
	}
}
예제 #3
0
/**
 * \brief Creates a boomerang.
 * \param hero the hero
 * \param max_distance maximum distance of the movement in pixels
 * \param speed speed of the movement in pixels per second
 * \param angle the angle of the boomerang trajectory in radians
 * \param sprite_name animation set id representing the boomerang
 */
Boomerang::Boomerang(
    const HeroPtr& hero,
    int max_distance,
    int speed,
    double angle,
    const std::string& sprite_name
):
  Entity("", 0, hero->get_layer(), Point(0, 0), Size(0, 0)),
  hero(hero),
  has_to_go_back(false),
  going_back(false),
  speed(speed) {

  // initialize the entity
  create_sprite(sprite_name);
  set_size(16, 16);
  set_origin(8, 8);

  int hero_x = hero->get_top_left_x();
  int hero_y = hero->get_top_left_y();
  switch (hero->get_animation_direction()) {

    case 0:
      set_xy(hero_x + 24, hero_y + 8);
      break;

    case 1:
      set_xy(hero_x + 8, hero_y - 8);
      break;

    case 2:
      set_xy(hero_x - 8, hero_y + 8);
      break;

    case 3:
      set_xy(hero_x + 8, hero_y + 24);
      break;

  }

  std::shared_ptr<StraightMovement> movement =
      std::make_shared<StraightMovement>(false, false);
  movement->set_speed(speed);
  movement->set_angle(angle);
  movement->set_max_distance(max_distance);
  set_movement(movement);

  next_sound_date = System::now();
}
예제 #4
0
void SkeletonAI::act(MonsterPtr monster) {
    HeroPtr hero = find_hero(monster);
    TilePtr tile = monster->get_pos();
    Coord coord  = tile->get_coord();
    if (hero) {
        TilePtr hero_tile = hero->get_pos();
        Coord hero_coord  = hero_tile->get_coord();
        if (can_atack(coord, hero_coord)) {
            atack(monster, hero);
        } else {
            Coord coord_to = small_path_search(coord, hero_coord);
            TilePtr tile_to = main_core->get_tile(coord_to);
            MovePtr move = Move::make_Ptr(monster, tile_to);
            main_core->do_action(move);
        }
    } else {
        make_move(monster);
    }
}
예제 #5
0
int3 whereToExplore(HeroPtr h)
{
	TimeCheck tc ("where to explore");
	int radius = h->getSightRadious();
	int3 hpos = h->visitablePos();

	SectorMap sm(h);

	//look for nearby objs -> visit them if they're close enouh
	const int DIST_LIMIT = 3;
	std::vector<const CGObjectInstance *> nearbyVisitableObjs;
	for (int x = hpos.x - DIST_LIMIT; x <= hpos.x + DIST_LIMIT; ++x) //get only local objects instead of all possible objects on the map
	{
		for (int y = hpos.y - DIST_LIMIT; y <= hpos.y + DIST_LIMIT; ++y)
		{
			for (auto obj : cb->getVisitableObjs (int3(x,y,hpos.z), false))
			{
				int3 op = obj->visitablePos();
				CGPath p;
				ai->myCb->getPathsInfo(h.get())->getPath(op, p);
				if (p.nodes.size() && p.endPos() == op && p.nodes.size() <= DIST_LIMIT)
					if (ai->isGoodForVisit(obj, h, sm))
						nearbyVisitableObjs.push_back(obj);
			}
		}
	}
	vstd::removeDuplicates (nearbyVisitableObjs); //one object may occupy multiple tiles
	boost::sort(nearbyVisitableObjs, CDistanceSorter(h.get()));
	if(nearbyVisitableObjs.size())
		return nearbyVisitableObjs.back()->visitablePos();

	try //check if nearby tiles allow us to reveal anything - this is quick
	{
		return ai->explorationBestNeighbour(hpos, radius, h);
	}
	catch(cannotFulfillGoalException &e)
	{
		//perform exhaustive search
		return ai->explorationNewPoint(h);
	}
}
예제 #6
0
파일: SectorMap.cpp 프로젝트: vcmi/vcmi
int3 SectorMap::findFirstVisitableTile(HeroPtr h, crint3 dst)
{
	int3 ret(-1, -1, -1);
	int3 curtile = dst;

	while (curtile != h->visitablePos())
	{
		auto topObj = cb->getTopObj(curtile);
		if (topObj && topObj->ID == Obj::HERO && topObj != h.h)
		{
			if (cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
			{
				logAi->warn("Another allied hero stands in our way");
				return ret;
			}
		}
		if (ai->myCb->getPathsInfo(h.get())->getPathInfo(curtile)->reachable())
		{
			return curtile;
		}
		else
		{
			auto i = parent.find(curtile);
			if (i != parent.end())
			{
				assert(curtile != i->second);
				curtile = i->second;
			}
			else
			{
				return ret;
				//throw cannotFulfillGoalException("Unreachable tile in sector? Should not happen!");
			}
		}
	}
	return ret;
}
예제 #7
0
파일: SectorMap.cpp 프로젝트: vcmi/vcmi
std::vector<const CGObjectInstance *> SectorMap::getNearbyObjs(HeroPtr h, bool sectorsAround)
{
	const Sector * heroSector = &infoOnSectors[retrieveTile(h->visitablePos())];
	if (sectorsAround)
	{
		std::vector<const CGObjectInstance *> ret;
		for (auto embarkPoint : heroSector->embarkmentPoints)
		{
			const Sector * embarkSector = &infoOnSectors[retrieveTile(embarkPoint)];
			range::copy(embarkSector->visitableObjs, std::back_inserter(ret));
		}
		return ret;
	}
	return heroSector->visitableObjs;
}
예제 #8
0
bool isSafeToVisit(HeroPtr h, crint3 tile)
{
	const ui64 heroStrength = h->getTotalStrength(),
		dangerStrength = evaluateDanger(tile, *h);
	if(dangerStrength)
	{
		if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength)
		{
            logAi->debugStream() << boost::format("It's, safe for %s to visit tile %s") % h->name % tile;
			return true;
		}
		else
			return false;
	}

	return true; //there's no danger
}
예제 #9
0
파일: SectorMap.cpp 프로젝트: vcmi/vcmi
SectorMap::SectorMap(HeroPtr h)
{
	update();
	makeParentBFS(h->visitablePos());
}
예제 #10
0
파일: SectorMap.cpp 프로젝트: vcmi/vcmi
/*
this functions returns one target tile or invalid tile. We will use it to poll possible destinations
For ship construction etc, another function (goal?) is needed
*/
int3 SectorMap::firstTileToGet(HeroPtr h, crint3 dst)
{
	int3 ret(-1, -1, -1);

	int sourceSector = retrieveTile(h->visitablePos());
	int destinationSector = retrieveTile(dst);

	const Sector * src = &infoOnSectors[sourceSector];
	const Sector * dest = &infoOnSectors[destinationSector];

	if (sourceSector != destinationSector) //use ships, shipyards etc..
	{
		if (ai->isAccessibleForHero(dst, h)) //pathfinder can find a way using ships and gates if tile is not blocked by objects
			return dst;

		std::map<const Sector *, const Sector *> preds;
		std::queue<const Sector *> sectorQueue;
		sectorQueue.push(src);
		while (!sectorQueue.empty())
		{
			const Sector * s = sectorQueue.front();
			sectorQueue.pop();

			for (int3 ep : s->embarkmentPoints)
			{
				Sector * neigh = &infoOnSectors[retrieveTile(ep)];
				//preds[s].push_back(neigh);
				if (!preds[neigh])
				{
					preds[neigh] = s;
					sectorQueue.push(neigh);
				}
			}
		}

		if (!preds[dest])
		{
			//write("test.txt");

			return ret;
			//throw cannotFulfillGoalException(boost::str(boost::format("Cannot find connection between sectors %d and %d") % src->id % dst->id));
		}

		std::vector<const Sector *> toTraverse;
		toTraverse.push_back(dest);
		while (toTraverse.back() != src)
		{
			toTraverse.push_back(preds[toTraverse.back()]);
		}

		if (preds[dest])
		{
			//TODO: would be nice to find sectors in loop
			const Sector * sectorToReach = toTraverse.at(toTraverse.size() - 2);

			if (!src->water && sectorToReach->water) //embark
			{
				//embark on ship -> look for an EP with a boat
				auto firstEP = boost::find_if(src->embarkmentPoints, [=](crint3 pos) -> bool
				{
					const TerrainTile * t = getTile(pos);
					if (t && t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT)
					{
						if (retrieveTile(pos) == sectorToReach->id)
							return true;
					}
					return false;
				});

				if (firstEP != src->embarkmentPoints.end())
				{
					return *firstEP;
				}
				else
				{
					//we need to find a shipyard with an access to the desired sector's EP
					//TODO what about Summon Boat spell?
					std::vector<const IShipyard *> shipyards;
					for (const CGTownInstance * t : cb->getTownsInfo())
					{
						if (t->hasBuilt(BuildingID::SHIPYARD))
							shipyards.push_back(t);
					}

					for (const CGObjectInstance * obj : ai->getFlaggedObjects())
					{
						if (obj->ID != Obj::TOWN) //towns were handled in the previous loop
						{
							if (const IShipyard * shipyard = IShipyard::castFrom(obj))
								shipyards.push_back(shipyard);
						}
					}

					shipyards.erase(boost::remove_if(shipyards, [=](const IShipyard * shipyard) -> bool
					{
						return shipyard->shipyardStatus() != 0 || retrieveTile(shipyard->bestLocation()) != sectorToReach->id;
					}), shipyards.end());

					if (!shipyards.size())
					{
						//TODO consider possibility of building shipyard in a town
						return ret;

						//throw cannotFulfillGoalException("There is no known shipyard!");
					}

					//we have only shipyards that possibly can build ships onto the appropriate EP
					auto ownedGoodShipyard = boost::find_if(shipyards, [](const IShipyard * s) -> bool
					{
						return s->o->tempOwner == ai->playerID;
					});

					if (ownedGoodShipyard != shipyards.end())
					{
						const IShipyard * s = *ownedGoodShipyard;
						TResources shipCost;
						s->getBoatCost(shipCost);
						if (cb->getResourceAmount().canAfford(shipCost))
						{
							int3 ret = s->bestLocation();
							cb->buildBoat(s); //TODO: move actions elsewhere
							return ret;
						}
						else
						{
							//TODO gather res
							return ret;

							//throw cannotFulfillGoalException("Not enough resources to build a boat");
						}
					}
					else
					{
						//TODO pick best shipyard to take over
						return shipyards.front()->o->visitablePos();
					}
				}
			}
			else if (src->water && !sectorToReach->water)
			{
				//TODO
				//disembark
				return ret;
			}
			else //use subterranean gates - not needed since gates are now handled via Pathfinder
			{
				return ret;
				//throw cannotFulfillGoalException("Land-land and water-water inter-sector transitions are not implemented!");
			}
		}
		else
		{
			return ret;
			//throw cannotFulfillGoalException("Inter-sector route detection failed: not connected sectors?");
		}
	}
	else //tiles are in same sector
	{
		return findFirstVisitableTile(h, dst);
	}
}
예제 #11
0
bool compareHeroStrength(HeroPtr h1, HeroPtr h2)
{
	return h1->getTotalStrength() < h2->getTotalStrength();
}