mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	AI: adding towns and dwellings to hero chain
This commit is contained in:
		
				
					committed by
					
						 Andrii Danylchenko
						Andrii Danylchenko
					
				
			
			
				
	
			
			
			
						parent
						
							8961f1c803
						
					
				
				
					commit
					3a0d9fe14e
				
			| @@ -201,11 +201,11 @@ bool isSafeToVisit(HeroPtr h, crint3 tile) | ||||
|  | ||||
| bool isSafeToVisit(HeroPtr h, const CCreatureSet * heroArmy, uint64_t dangerStrength) | ||||
| { | ||||
| 	const ui64 heroStrengthVariable = h->getFightingStrength() * heroArmy->getArmyStrength(); | ||||
| 	const ui64 heroStrength = h->getFightingStrength() * heroArmy->getArmyStrength(); | ||||
|  | ||||
| 	if(dangerStrength) | ||||
| 	{ | ||||
| 		if(heroStrengthVariable / SAFE_ATTACK_CONSTANT > dangerStrength) | ||||
| 		if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength) | ||||
| 		{ | ||||
| 			return true; | ||||
| 		} | ||||
|   | ||||
| @@ -291,6 +291,9 @@ void AINodeStorage::addHeroChain(AIPathNode * srcNode, std::vector<AIPathNode *> | ||||
|  | ||||
| void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other) | ||||
| { | ||||
| 	if(!carrier->actor->isMovable) | ||||
| 		return; | ||||
| 	 | ||||
| 	if(carrier->actor->canExchange(other->actor)) | ||||
| 	{ | ||||
| #ifdef VCMI_TRACE_PATHFINDER_EX | ||||
| @@ -421,7 +424,52 @@ void AINodeStorage::setHeroes(std::vector<HeroPtr> heroes, const VCAI * _ai) | ||||
| 	{ | ||||
| 		uint64_t mask = 1 << actors.size(); | ||||
|  | ||||
| 		actors.push_back(std::make_shared<HeroActor>(hero.get(), mask)); | ||||
| 		actors.push_back(std::make_shared<HeroActor>(hero.get(), mask, ai)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AINodeStorage::setTownsAndDwellings( | ||||
| 	const std::vector<const CGTownInstance *> & towns, | ||||
| 	const std::vector<const CGObjectInstance *> & visitableObjs) | ||||
| { | ||||
| 	for(auto town : towns) | ||||
| 	{ | ||||
| 		uint64_t mask = 1 << actors.size(); | ||||
|  | ||||
| 		if(town->getUpperArmy()->getArmyStrength()) | ||||
| 		{ | ||||
| 			actors.push_back(std::make_shared<TownGarrisonActor>(town, mask)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	auto dayOfWeek = cb->getDate(Date::DAY_OF_WEEK); | ||||
| 	auto waitForGrowth = dayOfWeek > 4; | ||||
|  | ||||
| 	for(auto obj: visitableObjs) | ||||
| 	{ | ||||
| 		const CGDwelling * dwelling = dynamic_cast<const CGDwelling *>(obj); | ||||
|  | ||||
| 		if(dwelling) | ||||
| 		{ | ||||
| 			uint64_t mask = 1 << actors.size(); | ||||
| 			auto dwellingActor = std::make_shared<DwellingActor>(dwelling, mask, false, dayOfWeek); | ||||
|  | ||||
| 			if(dwellingActor->creatureSet->getArmyStrength()) | ||||
| 			{ | ||||
| 				actors.push_back(dwellingActor); | ||||
| 			} | ||||
|  | ||||
| 			if(waitForGrowth) | ||||
| 			{ | ||||
| 				mask = 1 << actors.size(); | ||||
| 				dwellingActor = std::make_shared<DwellingActor>(dwelling, mask, waitForGrowth, dayOfWeek); | ||||
|  | ||||
| 				if(dwellingActor->creatureSet->getArmyStrength()) | ||||
| 				{ | ||||
| 					actors.push_back(dwellingActor); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -22,8 +22,6 @@ | ||||
| #include "Actors.h" | ||||
| #include <inttypes.h> | ||||
|  | ||||
| #define VCMI_TRACE_PATHFINDER | ||||
|  | ||||
| struct AIPathNode : public CGPathNode | ||||
| { | ||||
| 	uint64_t danger; | ||||
| @@ -116,6 +114,9 @@ public: | ||||
| 	std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const; | ||||
| 	bool isTileAccessible(const HeroPtr & hero, const int3 & pos, const EPathfindingLayer layer) const; | ||||
| 	void setHeroes(std::vector<HeroPtr> heroes, const VCAI * ai); | ||||
| 	void setTownsAndDwellings( | ||||
| 		const std::vector<const CGTownInstance *> & towns, | ||||
| 		const std::vector<const CGObjectInstance *> & visitableObjs); | ||||
| 	const CGHeroInstance * getHero(const CGPathNode * node) const; | ||||
| 	const std::set<const CGHeroInstance *> getAllHeroes() const; | ||||
| 	void clear(); | ||||
|   | ||||
| @@ -65,4 +65,4 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain) | ||||
| 		logAi->trace("Recalculate chain pass %" PRIi32, pass); | ||||
| 		useHeroChain = useHeroChain && storage->calculateHeroChain(); | ||||
| 	} while(useHeroChain); | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -9,12 +9,13 @@ | ||||
| */ | ||||
| #include "StdInc.h" | ||||
| #include "Actors.h" | ||||
| #include "../Goals/VisitHero.h" | ||||
| #include "../VCAI.h" | ||||
| #include "../AIhelper.h" | ||||
| #include "../../../CCallback.h" | ||||
| #include "../../../lib/mapping/CMap.h" | ||||
| #include "../../../lib/mapObjects/MapObjects.h" | ||||
|  | ||||
| #include "../Goals/VisitHero.h" | ||||
|  | ||||
| class ExchangeAction : public ISpecialAction | ||||
| { | ||||
| private: | ||||
| @@ -32,44 +33,49 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| ChainActor::ChainActor(const CGHeroInstance * hero, int chainMask) | ||||
| 	:hero(hero), isMovable(true), chainMask(chainMask), creatureSet(hero), carrierParent(nullptr), otherParent(nullptr) | ||||
| ChainActor::ChainActor(const CGHeroInstance * hero, uint64_t chainMask) | ||||
| 	:hero(hero), isMovable(true), chainMask(chainMask), creatureSet(hero), | ||||
| 	baseActor(this), carrierParent(nullptr), otherParent(nullptr) | ||||
| { | ||||
| 	baseActor = static_cast<HeroActor *>(this); | ||||
| 	initialPosition = hero->visitablePos(); | ||||
| 	layer = hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND; | ||||
| 	initialMovement = hero->movement; | ||||
| 	initialTurn = 0; | ||||
| 	armyValue = hero->getTotalStrength(); | ||||
| 	armyValue = hero->getArmyStrength(); | ||||
| } | ||||
|  | ||||
| ChainActor::ChainActor(const ChainActor * carrier, const ChainActor * other, const CCreatureSet * heroArmy) | ||||
| 	:hero(carrier->hero), isMovable(true), creatureSet(heroArmy), initialPosition(-1), | ||||
| 	carrierParent(carrier), otherParent(other), chainMask(carrier->chainMask | other->chainMask) | ||||
| 	:hero(carrier->hero), isMovable(true), creatureSet(heroArmy), chainMask(carrier->chainMask | other->chainMask), | ||||
| 	baseActor(this), carrierParent(carrier), otherParent(other) | ||||
| { | ||||
| 	baseActor = static_cast<HeroActor *>(this); | ||||
| 	armyValue = hero->getFightingStrength() * heroArmy->getArmyStrength(); | ||||
| 	armyValue = heroArmy->getArmyStrength(); | ||||
| } | ||||
|  | ||||
| HeroActor::HeroActor(const CGHeroInstance * hero, int chainMask) | ||||
| ChainActor::ChainActor(const CGObjectInstance * obj, const CCreatureSet * creatureSet, uint64_t chainMask, int initialTurn) | ||||
| 	:hero(nullptr), isMovable(false), creatureSet(creatureSet), chainMask(chainMask), | ||||
| 	baseActor(this), carrierParent(nullptr), otherParent(nullptr), initialTurn(initialTurn), initialMovement(0) | ||||
| { | ||||
| 	initialPosition = obj->visitablePos(); | ||||
| 	layer = EPathfindingLayer::LAND; | ||||
| 	armyValue = creatureSet->getArmyStrength(); | ||||
| } | ||||
|  | ||||
| HeroActor::HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai) | ||||
| 	:ChainActor(hero, chainMask) | ||||
| { | ||||
| 	exchangeMap = new HeroExchangeMap(this, ai); | ||||
| 	setupSpecialActors(); | ||||
| } | ||||
|  | ||||
| HeroActor::HeroActor(const ChainActor * carrier, const ChainActor * other) | ||||
| 	:ChainActor( | ||||
| 		carrier,  | ||||
| 		other, | ||||
| 		pickBestCreatures(carrier->creatureSet, other->creatureSet)) | ||||
| HeroActor::HeroActor( | ||||
| 	const ChainActor * carrier,  | ||||
| 	const ChainActor * other,  | ||||
| 	const CCreatureSet * army,  | ||||
| 	const VCAI * ai) | ||||
| 	:ChainActor(carrier, other,	army) | ||||
| { | ||||
| 	exchangeMap = new HeroExchangeMap(this, ai); | ||||
| 	setupSpecialActors(); | ||||
| 	exchangeAction.reset(new ExchangeAction(carrier->hero, other->hero)); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<ISpecialAction> ChainActor::getExchangeAction() const | ||||
| {  | ||||
| 	return baseActor->exchangeAction;  | ||||
| } | ||||
|  | ||||
| void ChainActor::setBaseActor(HeroActor * base) | ||||
| @@ -108,14 +114,14 @@ void HeroActor::setupSpecialActors() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| ChainActor * ChainActor::exchange(const ChainActor * other) const | ||||
| ChainActor * ChainActor::exchange(const ChainActor * specialActor, const ChainActor * other) const | ||||
| { | ||||
| 	return baseActor->exchange(this, other); | ||||
| 	return baseActor->exchange(specialActor, other); | ||||
| } | ||||
|  | ||||
| bool ChainActor::canExchange(const ChainActor * other) const | ||||
| { | ||||
| 	return baseActor->canExchange(other->baseActor); | ||||
| 	return isMovable && baseActor->canExchange(other); | ||||
| } | ||||
|  | ||||
| namespace vstd | ||||
| @@ -135,68 +141,124 @@ namespace vstd | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool HeroActor::canExchange(const HeroActor * other) | ||||
| bool HeroActor::canExchange(const ChainActor * other) const | ||||
| { | ||||
| 	return exchangeMap->canExchange(other); | ||||
| } | ||||
|  | ||||
| bool HeroExchangeMap::canExchange(const ChainActor * other) | ||||
| { | ||||
| 	return vstd::getOrCompute(canExchangeCache, other, [&](bool & result) { | ||||
| 		result = (chainMask & other->chainMask) == 0 | ||||
| 			&& howManyReinforcementsCanGet(creatureSet, other->creatureSet) > armyValue / 10; | ||||
| 		result = (actor->chainMask & other->chainMask) == 0; | ||||
|  | ||||
| 		if(result) | ||||
| 		{ | ||||
| 			uint64_t reinforcment = ai->ah->howManyReinforcementsCanGet(actor->creatureSet, other->creatureSet); | ||||
|  | ||||
| 			result = reinforcment > actor->armyValue / 10 || reinforcment > 1000; | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| ChainActor * HeroActor::exchange(const ChainActor * specialActor, const ChainActor * other) | ||||
| ChainActor * HeroActor::exchange(const ChainActor * specialActor, const ChainActor * other) const | ||||
| { | ||||
| 	HeroActor * result; | ||||
| 	const HeroActor * otherBase = other->getBaseActor(); | ||||
|  | ||||
| 	if(vstd::contains(exchangeMap, otherBase)) | ||||
| 		result = exchangeMap.at(otherBase); | ||||
| 	else  | ||||
| 	{ | ||||
| 		// TODO: decide where to release this CCreatureSet and HeroActor. Probably custom ~ctor? | ||||
| 		result = new HeroActor(specialActor, other); | ||||
| 		exchangeMap[otherBase] = result; | ||||
| 	} | ||||
| 	const ChainActor * otherBase = other->baseActor; | ||||
| 	HeroActor * result = exchangeMap->exchange(otherBase); | ||||
|  | ||||
| 	if(specialActor == this) | ||||
| 		return result; | ||||
|  | ||||
| 	int index = vstd::find_pos_if(specialActors, [specialActor](const ChainActor & actor) -> bool {  | ||||
| 	int index = vstd::find_pos_if(specialActors, [specialActor](const ChainActor & actor) -> bool | ||||
| 	{ | ||||
| 		return &actor == specialActor; | ||||
| 	}); | ||||
|  | ||||
| 	return &result->specialActors[index]; | ||||
| } | ||||
|  | ||||
| CCreatureSet * HeroActor::pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const | ||||
| HeroActor * HeroExchangeMap::exchange(const ChainActor * other) | ||||
| { | ||||
| 	HeroActor * result; | ||||
|  | ||||
| 	if(vstd::contains(exchangeMap, other)) | ||||
| 		result = exchangeMap.at(other); | ||||
| 	else  | ||||
| 	{ | ||||
| 		// TODO: decide where to release this CCreatureSet and HeroActor. Probably custom ~ctor? | ||||
| 		CCreatureSet * newArmy = pickBestCreatures(actor->creatureSet, other->creatureSet); | ||||
| 		result = new HeroActor(actor, other, newArmy, ai); | ||||
| 		exchangeMap[other] = result; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CCreatureSet * HeroExchangeMap::pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const | ||||
| { | ||||
| 	CCreatureSet * target = new CCreatureSet(); | ||||
| 	const CCreatureSet * armies[] = { army1, army2 }; | ||||
| 	auto bestArmy = ai->ah->getBestArmy(army1, army2); | ||||
|  | ||||
| 	//we calculate total strength for each creature type available in armies | ||||
| 	std::map<const CCreature *, int> creToPower; | ||||
| 	for(auto armyPtr : armies) | ||||
| 	for(auto & slotInfo : bestArmy) | ||||
| 	{ | ||||
| 		for(auto & i : armyPtr->Slots()) | ||||
| 		{ | ||||
| 			creToPower[i.second->type] += i.second->count; | ||||
| 		} | ||||
| 	} | ||||
| 	//TODO - consider more than just power (ie morale penalty, hero specialty in certain stacks, etc) | ||||
| 	int armySize = creToPower.size(); | ||||
| 		auto targetSlot = target->getFreeSlot(); | ||||
|  | ||||
| 	vstd::amin(armySize, GameConstants::ARMY_SIZE); | ||||
|  | ||||
| 	for(int i = 0; i < armySize && !creToPower.empty(); i++) //pick the creatures from which we can get most power, as many as dest can fit | ||||
| 	{ | ||||
| 		typedef const std::pair<const CCreature *, int> & CrePowerPair; | ||||
| 		auto creIt = boost::max_element(creToPower, [](CrePowerPair lhs, CrePowerPair rhs) | ||||
| 		{ | ||||
| 			return lhs.first->AIValue * lhs.second < rhs.first->AIValue * rhs.second; | ||||
| 		}); | ||||
|  | ||||
| 		target->addToSlot(SlotID(i), creIt->first->idNumber, TQuantity(creIt->second)); | ||||
| 		creToPower.erase(creIt); | ||||
| 		target->addToSlot(targetSlot, slotInfo.creature->idNumber, TQuantity(slotInfo.count)); | ||||
| 	} | ||||
|  | ||||
| 	return target; | ||||
| } | ||||
|  | ||||
| DwellingActor::DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bool waitForGrowth, int dayOfWeek) | ||||
| 	:ChainActor( | ||||
| 		dwelling,  | ||||
| 		getDwellingCreatures(dwelling, waitForGrowth),  | ||||
| 		chainMask,  | ||||
| 		getInitialTurn(waitForGrowth, dayOfWeek)) | ||||
| { | ||||
| } | ||||
|  | ||||
| DwellingActor::~DwellingActor() | ||||
| { | ||||
| 	delete creatureSet; | ||||
| } | ||||
|  | ||||
| int DwellingActor::getInitialTurn(bool waitForGrowth, int dayOfWeek) | ||||
| { | ||||
| 	if(!waitForGrowth) | ||||
| 		return 0; | ||||
|  | ||||
| 	return 8 - dayOfWeek; | ||||
| } | ||||
|  | ||||
| CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling, bool waitForGrowth) | ||||
| { | ||||
| 	CCreatureSet * dwellingCreatures = new CCreatureSet(); | ||||
|  | ||||
| 	for(auto & creatureInfo : dwelling->creatures) | ||||
| 	{ | ||||
| 		if(!creatureInfo.second.size()) | ||||
| 			continue; | ||||
|  | ||||
| 		auto creature = creatureInfo.second.back().toCreature(); | ||||
| 		auto count = creatureInfo.first; | ||||
| 			 | ||||
| 		if(waitForGrowth) | ||||
| 		{ | ||||
| 			const CGTownInstance * town = dynamic_cast<const CGTownInstance *>(dwelling); | ||||
|  | ||||
| 			count += town ? town->creatureGrowth(creature->level) : creature->growth; | ||||
| 		} | ||||
|  | ||||
| 		dwellingCreatures->addToSlot( | ||||
| 			dwellingCreatures->getSlotFor(creature), | ||||
| 			creature->idNumber, | ||||
| 			TQuantity(creatureInfo.first)); | ||||
| 	} | ||||
|  | ||||
| 	return dwellingCreatures; | ||||
| } | ||||
|  | ||||
| TownGarrisonActor::TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask) | ||||
| 	:ChainActor(town, town->getUpperArmy(), chainMask, 0) | ||||
| { | ||||
| } | ||||
| @@ -16,13 +16,14 @@ | ||||
| #include "Actions/ISpecialAction.h" | ||||
|  | ||||
| class HeroActor; | ||||
| class VCAI; | ||||
|  | ||||
| class ChainActor | ||||
| { | ||||
| protected: | ||||
| 	HeroActor * baseActor; | ||||
| 	ChainActor(const CGHeroInstance * hero, int chainMask); | ||||
| 	ChainActor(const CGHeroInstance * hero, uint64_t chainMask); | ||||
| 	ChainActor(const ChainActor * carrier, const ChainActor * other, const CCreatureSet * heroArmy); | ||||
| 	ChainActor(const CGObjectInstance * obj, const CCreatureSet * army, uint64_t chainMask, int initialTurn); | ||||
|  | ||||
| public: | ||||
| 	uint64_t chainMask; | ||||
| @@ -37,6 +38,7 @@ public: | ||||
| 	const ChainActor * resourceActor; | ||||
| 	const ChainActor * carrierParent; | ||||
| 	const ChainActor * otherParent; | ||||
| 	const ChainActor * baseActor; | ||||
| 	int3 initialPosition; | ||||
| 	EPathfindingLayer layer; | ||||
| 	uint32_t initialMovement; | ||||
| @@ -44,12 +46,34 @@ public: | ||||
| 	uint64_t armyValue; | ||||
|  | ||||
| 	ChainActor(){} | ||||
| 	ChainActor * exchange(const ChainActor * other) const; | ||||
| 	bool canExchange(const ChainActor * other) const; | ||||
| 	void setBaseActor(HeroActor * base); | ||||
| 	const HeroActor * getBaseActor() const { return baseActor; } | ||||
| 	std::shared_ptr<ISpecialAction> getExchangeAction() const; | ||||
|  | ||||
| 	virtual bool canExchange(const ChainActor * other) const; | ||||
| 	ChainActor * exchange(const ChainActor * other) const { return exchange(this, other); } | ||||
| 	void setBaseActor(HeroActor * base); | ||||
|  | ||||
| protected: | ||||
| 	virtual ChainActor * exchange(const ChainActor * specialActor, const ChainActor * other) const; | ||||
| }; | ||||
|  | ||||
| class HeroExchangeMap | ||||
| { | ||||
| private: | ||||
| 	const HeroActor * actor; | ||||
| 	std::map<const ChainActor *, HeroActor *> exchangeMap; | ||||
| 	std::map<const ChainActor *, bool> canExchangeCache; | ||||
| 	const VCAI * ai; | ||||
|  | ||||
| public: | ||||
| 	HeroExchangeMap(const HeroActor * actor, const VCAI * ai) | ||||
| 		:actor(actor), ai(ai) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	HeroActor * exchange(const ChainActor * other); | ||||
| 	bool canExchange(const ChainActor * other); | ||||
|  | ||||
| private: | ||||
| 	CCreatureSet * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const; | ||||
| }; | ||||
|  | ||||
| class HeroActor : public ChainActor | ||||
| @@ -59,8 +83,7 @@ public: | ||||
|  | ||||
| private: | ||||
| 	ChainActor specialActors[SPECIAL_ACTORS_COUNT]; | ||||
| 	std::map<const ChainActor *, HeroActor *> exchangeMap; | ||||
| 	std::map<const HeroActor *, bool> canExchangeCache; | ||||
| 	HeroExchangeMap * exchangeMap; | ||||
|  | ||||
| 	void setupSpecialActors(); | ||||
|  | ||||
| @@ -68,13 +91,28 @@ public: | ||||
| 	std::shared_ptr<ISpecialAction> exchangeAction; | ||||
| 	// chain flags, can be combined meaning hero exchange and so on | ||||
|  | ||||
| 	HeroActor() | ||||
| 	{ | ||||
| 	} | ||||
| 	HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai); | ||||
| 	HeroActor(const ChainActor * carrier, const ChainActor * other, const CCreatureSet * army, const VCAI * ai); | ||||
|  | ||||
| 	HeroActor(const CGHeroInstance * hero, int chainMask); | ||||
| 	HeroActor(const ChainActor * carrier, const ChainActor * other); | ||||
| 	ChainActor * exchange(const ChainActor * specialActor, const ChainActor * other); | ||||
| 	bool canExchange(const HeroActor * other); | ||||
| 	CCreatureSet * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const; | ||||
| 	virtual bool canExchange(const ChainActor * other) const override; | ||||
|  | ||||
| protected: | ||||
| 	virtual ChainActor * exchange(const ChainActor * specialActor, const ChainActor * other) const override; | ||||
| }; | ||||
|  | ||||
| class DwellingActor : public ChainActor | ||||
| { | ||||
| public: | ||||
| 	DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bool waitForGrowth, int dayOfWeek); | ||||
| 	~DwellingActor(); | ||||
|  | ||||
| protected: | ||||
| 	int getInitialTurn(bool waitForGrowth, int dayOfWeek); | ||||
| 	CCreatureSet * getDwellingCreatures(const CGDwelling * dwelling, bool waitForGrowth); | ||||
| }; | ||||
|  | ||||
| class TownGarrisonActor : public ChainActor | ||||
| { | ||||
| public: | ||||
| 	TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask); | ||||
| }; | ||||
| @@ -127,7 +127,7 @@ namespace AIPathfinding | ||||
| 			auto hero = nodeStorage->getHero(source.node); | ||||
| 			auto danger = nodeStorage->evaluateDanger(destination.coord, hero); | ||||
| 			double actualArmyValue = srcNode->actor->armyValue - srcNode->armyLoss; | ||||
| 			double ratio = (double)danger / actualArmyValue; | ||||
| 			double ratio = (double)danger / (actualArmyValue * hero->getFightingStrength()); | ||||
|  | ||||
| 			uint64_t loss = (uint64_t)(actualArmyValue * ratio * ratio * ratio); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user