ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor) { const TerrainTile *t = cb->getTile(tile, false); if(!t) //we can know about guard but can't check its tile (the edge of fow) return 190000000; //MUCH ui64 objectDanger = 0, guardDanger = 0; auto visitableObjects = cb->getVisitableObjs(tile); // in some scenarios hero happens to be "under" the object (eg town). Then we consider ONLY the hero. if(vstd::contains_if(visitableObjects, objWithID<Obj::HERO>)) vstd::erase_if(visitableObjects, [](const CGObjectInstance * obj) { return !objWithID<Obj::HERO>(obj); }); if(const CGObjectInstance * dangerousObject = vstd::backOrNull(visitableObjects)) { objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled if (objectDanger) { //TODO: don't downcast objects AI shouldn't know about! auto armedObj = dynamic_cast<const CArmedInstance*>(dangerousObject); if (armedObj) { float tacticalAdvantage = fh->getTacticalAdvantage(visitor, armedObj); objectDanger *= tacticalAdvantage; //this line tends to go infinite for allied towns (?) } } if (dangerousObject->ID == Obj::SUBTERRANEAN_GATE) { //check guard on the other side of the gate auto it = ai->knownSubterraneanGates.find(dangerousObject); if (it != ai->knownSubterraneanGates.end()) { auto guards = cb->getGuardingCreatures(it->second->visitablePos()); for (auto cre : guards) { vstd::amax (guardDanger, evaluateDanger(cre) * fh->getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance*>(cre))); } } } } auto guards = cb->getGuardingCreatures(tile); for (auto cre : guards) { vstd::amax (guardDanger, evaluateDanger(cre) * fh->getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance*>(cre))); //we are interested in strongest monster around } //TODO mozna odwiedzic blockvis nie ruszajac straznika return std::max(objectDanger, guardDanger); }
ui64 evaluateDanger(crint3 tile) { const TerrainTile *t = cb->getTile(tile, false); if(!t) //we can know about guard but can't check its tile (the edge of fow) return 190000000; //MUCH ui64 objectDanger = 0, guardDanger = 0; auto visObjs = cb->getVisitableObjs(tile); if(visObjs.size()) objectDanger = evaluateDanger(visObjs.back()); int3 guardPos = cb->guardingCreaturePosition(tile); if(guardPos.x >= 0 && guardPos != tile) guardDanger = evaluateDanger(guardPos); //TODO mozna odwiedzic blockvis nie ruszajac straznika return std::max(objectDanger, guardDanger); }
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 }
bool compareDanger(const CGObjectInstance *lhs, const CGObjectInstance *rhs) { return evaluateDanger(lhs) < evaluateDanger(rhs); }