/* * BuildingManager.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "ArmyManager.h" #include "../../CCallback.h" #include "../../lib/mapObjects/MapObjects.h" void ArmyManager::init(CPlayerSpecificInfoCallback * CB) { cb = CB; } void ArmyManager::setAI(VCAI * AI) { ai = AI; } std::vector ArmyManager::getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const { const CCreatureSet * armies[] = { target, source }; //we calculate total strength for each creature type available in armies std::map creToPower; std::vector resultingArmy; for(auto armyPtr : armies) { for(auto & i : armyPtr->Slots()) { auto cre = dynamic_cast(i.second->type); auto & slotInfp = creToPower[cre]; slotInfp.creature = cre; slotInfp.power += i.second->getPower(); slotInfp.count += i.second->count; } } for(auto pair : creToPower) resultingArmy.push_back(pair.second); boost::sort(resultingArmy, [](const SlotInfo & left, const SlotInfo & right) -> bool { return left.power > right.power; }); return resultingArmy; } std::vector::iterator ArmyManager::getWeakestCreature(std::vector & army) const { auto weakest = boost::min_element(army, [](const SlotInfo & left, const SlotInfo & right) -> bool { if(left.creature->getLevel() != right.creature->getLevel()) return left.creature->getLevel() < right.creature->getLevel(); return left.creature->getMovementRange() > right.creature->getMovementRange(); }); return weakest; } std::vector ArmyManager::getBestArmy(const CCreatureSet * target, const CCreatureSet * source) const { auto resultingArmy = getSortedSlots(target, source); if(resultingArmy.size() > GameConstants::ARMY_SIZE) { resultingArmy.resize(GameConstants::ARMY_SIZE); } else if(source->needsLastStack()) { auto weakest = getWeakestCreature(resultingArmy); if(weakest->count == 1) { resultingArmy.erase(weakest); } else { weakest->power -= weakest->power / weakest->count; weakest->count--; } } return resultingArmy; } bool ArmyManager::canGetArmy(const CArmedInstance * target, const CArmedInstance * source) const { //TODO: merge with pickBestCreatures //if (ai->primaryHero().h == source) if(target->tempOwner != source->tempOwner) { logAi->error("Why are we even considering exchange between heroes from different players?"); return false; } return 0 < howManyReinforcementsCanGet(target, source); } ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDwelling * t) const { ui64 aivalue = 0; TResources availableRes = cb->getResourceAmount(); int freeHeroSlots = GameConstants::ARMY_SIZE - h->stacksCount(); for(auto const & dc : t->creatures) { creInfo ci = infoFromDC(dc); if(!ci.count || ci.creID == CreatureID::NONE) continue; vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford if(ci.count && ci.creID != CreatureID::NONE) //valid creature at this level { //can be merged with another stack? SlotID dst = h->getSlotFor(ci.creID); if(!h->hasStackAtSlot(dst)) //need another new slot for this stack { if(!freeHeroSlots) //no more place for stacks continue; else freeHeroSlots--; //new slot will be occupied } //we found matching occupied or free slot aivalue += ci.count * ci.cre->getAIValue(); availableRes -= ci.cre->getFullRecruitCost() * ci.count; } } return aivalue; } ui64 ArmyManager::howManyReinforcementsCanGet(const CCreatureSet * target, const CCreatureSet * source) const { auto bestArmy = getBestArmy(target, source); uint64_t newArmy = 0; uint64_t oldArmy = target->getArmyStrength(); for(auto & slot : bestArmy) { newArmy += slot.power; } return newArmy > oldArmy ? newArmy - oldArmy : 0; }