mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-29 23:07:48 +02:00
hero chain stabilisation
This commit is contained in:
committed by
Andrii Danylchenko
parent
87f1079c60
commit
774f531c4e
@@ -132,7 +132,8 @@ std::vector<CGPathNode *> AINodeStorage::getInitialNodes()
|
||||
initialNode->turns = actor->initialTurn;
|
||||
initialNode->moveRemains = actor->initialMovement;
|
||||
initialNode->danger = 0;
|
||||
initialNode->cost = 0.0;
|
||||
initialNode->cost = actor->initialTurn;
|
||||
initialNode->action = CGPathNode::ENodeAction::NORMAL;
|
||||
|
||||
if(actor->isMovable)
|
||||
{
|
||||
@@ -175,6 +176,16 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf
|
||||
{
|
||||
dstNode->specialAction->applyOnDestination(dstNode->actor->hero, destination, source, dstNode, srcNode);
|
||||
}
|
||||
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace(
|
||||
"Commited %s -> %s, cost: %f, hero: %s, mask: %i",
|
||||
source.coord.toString(),
|
||||
destination.coord.toString(),
|
||||
destination.cost,
|
||||
dstNode->actor->hero->name,
|
||||
dstNode->actor->chainMask);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
@@ -194,6 +205,7 @@ void AINodeStorage::commit(
|
||||
destination->manaCost = source->manaCost;
|
||||
destination->danger = source->danger;
|
||||
destination->theNodeBefore = source->theNodeBefore;
|
||||
destination->chainOther = nullptr;
|
||||
}
|
||||
|
||||
std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
|
||||
@@ -227,33 +239,53 @@ bool AINodeStorage::calculateHeroChain()
|
||||
heroChainPass = true;
|
||||
heroChain.resize(0);
|
||||
|
||||
std::vector<AIPathNode *> buffer;
|
||||
|
||||
buffer.reserve(NUM_CHAINS);
|
||||
|
||||
foreach_tile_pos([&](const int3 & pos) {
|
||||
auto layer = EPathfindingLayer::LAND;
|
||||
auto chains = nodes[pos.x][pos.y][pos.z][layer];
|
||||
|
||||
buffer.resize(0);
|
||||
|
||||
for(AIPathNode & node : chains)
|
||||
{
|
||||
if(node.locked && node.turns < 1)
|
||||
addHeroChain(&node);
|
||||
if(node.turns <= heroChainMaxTurns && node.action != CGPathNode::ENodeAction::UNKNOWN)
|
||||
buffer.push_back(&node);
|
||||
}
|
||||
|
||||
for(AIPathNode * node : buffer)
|
||||
{
|
||||
addHeroChain(node, buffer);
|
||||
}
|
||||
});
|
||||
|
||||
return heroChain.size();
|
||||
}
|
||||
|
||||
void AINodeStorage::addHeroChain(AIPathNode * srcNode)
|
||||
void AINodeStorage::addHeroChain(AIPathNode * srcNode, std::vector<AIPathNode *> variants)
|
||||
{
|
||||
auto chains = nodes[srcNode->coord.x][srcNode->coord.y][srcNode->coord.z][srcNode->layer];
|
||||
|
||||
for(AIPathNode & node : chains)
|
||||
for(AIPathNode * node : variants)
|
||||
{
|
||||
if(!node.locked || !node.actor || node.action == CGPathNode::ENodeAction::UNKNOWN && node.actor->hero)
|
||||
if(node == srcNode || !node->actor || node->turns > heroChainMaxTurns
|
||||
|| node->action == CGPathNode::ENodeAction::UNKNOWN && node->actor->hero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
addHeroChain(srcNode, &node);
|
||||
addHeroChain(&node, srcNode);
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace(
|
||||
"Thy exchange %s[%i] -> %s[%i] at %s",
|
||||
node->actor->hero->name,
|
||||
node->actor->chainMask,
|
||||
srcNode->actor->hero->name,
|
||||
srcNode->actor->chainMask,
|
||||
srcNode->coord.toString());
|
||||
#endif
|
||||
|
||||
addHeroChain(srcNode, node);
|
||||
//addHeroChain(&node, srcNode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,37 +293,65 @@ void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other)
|
||||
{
|
||||
if(carrier->actor->canExchange(other->actor))
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace(
|
||||
"Exchange allowed %s[%i] -> %s[%i] at %s",
|
||||
other->actor->hero->name,
|
||||
other->actor->chainMask,
|
||||
carrier->actor->hero->name,
|
||||
carrier->actor->chainMask,
|
||||
carrier->coord.toString());
|
||||
#endif
|
||||
|
||||
bool hasLessMp = carrier->turns > other->turns || carrier->moveRemains < other->moveRemains;
|
||||
bool hasLessExperience = carrier->actor->hero->exp < other->actor->hero->exp;
|
||||
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace("Check hero exhange at %s, %s -> %s", carrier->coord.toString(), other->actor->hero->name, carrier->actor->hero->name);
|
||||
#endif
|
||||
|
||||
if(hasLessMp && hasLessExperience)
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace("Exchange at %s is ineficient. Blocked.", carrier->coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
auto newActor = carrier->actor->exchange(other->actor);
|
||||
auto chainNodeOptional = getOrCreateNode(carrier->coord, carrier->layer, newActor);
|
||||
|
||||
if(!chainNodeOptional)
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace("Exchange at %s can not allocate node. Blocked.", carrier->coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
auto chainNode = chainNodeOptional.get();
|
||||
|
||||
if(chainNode->locked)
|
||||
return;
|
||||
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace("Hero exhange at %s, %s -> %s", carrier->coord.toString(), other->actor->hero->name, carrier->actor->hero->name);
|
||||
if(chainNode->action != CGPathNode::ENodeAction::UNKNOWN)
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace("Exchange at %s node is already in use. Blocked.", carrier->coord.toString());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
commitExchange(chainNode, carrier, other);
|
||||
heroChain.push_back(chainNode);
|
||||
if(commitExchange(chainNode, carrier, other))
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace(
|
||||
"Chain accepted at %s %s -> %s, mask %i, cost %f",
|
||||
chainNode->coord.toString(),
|
||||
other->actor->hero->name,
|
||||
chainNode->actor->hero->name,
|
||||
chainNode->actor->chainMask,
|
||||
chainNode->cost);
|
||||
#endif
|
||||
heroChain.push_back(chainNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AINodeStorage::commitExchange(
|
||||
bool AINodeStorage::commitExchange(
|
||||
AIPathNode * exchangeNode,
|
||||
AIPathNode * carrierParentNode,
|
||||
AIPathNode * otherParentNode) const
|
||||
@@ -302,7 +362,7 @@ void AINodeStorage::commitExchange(
|
||||
|
||||
auto armyLoss = carrierParentNode->armyLoss + otherParentNode->armyLoss;
|
||||
auto turns = carrierParentNode->turns;
|
||||
auto cost = carrierParentNode->cost;
|
||||
auto cost = carrierParentNode->cost + otherParentNode->cost / 1000.0;
|
||||
auto movementLeft = carrierParentNode->moveRemains;
|
||||
|
||||
if(carrierParentNode->turns < otherParentNode->turns)
|
||||
@@ -312,27 +372,24 @@ void AINodeStorage::commitExchange(
|
||||
+ carrierParentNode->moveRemains / (float)moveRemains;
|
||||
|
||||
turns = otherParentNode->turns;
|
||||
cost = waitingCost;
|
||||
cost += waitingCost;
|
||||
movementLeft = moveRemains;
|
||||
}
|
||||
|
||||
if(exchangeNode->turns != 0xFF && exchangeNode->cost < cost)
|
||||
return;
|
||||
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
"Accepted hero exhange at %s, carrier %s, mp cost %f",
|
||||
exchangeNode->coord.toString(),
|
||||
carrierActor->hero->name,
|
||||
cost);
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER_EX
|
||||
logAi->trace("Exchange at %s is is not effective enough. %f < %f", exchangeNode->coord.toString(), exchangeNode->cost, cost);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
commit(exchangeNode, carrierParentNode, carrierParentNode->action, turns, movementLeft, cost);
|
||||
|
||||
exchangeNode->theNodeBefore = carrierParentNode;
|
||||
exchangeNode->chainOther = otherParentNode;
|
||||
exchangeNode->armyLoss = armyLoss;
|
||||
exchangeNode->manaCost = carrierParentNode->manaCost;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const CGHeroInstance * AINodeStorage::getHero(const CGPathNode * node) const
|
||||
@@ -538,6 +595,7 @@ std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand)
|
||||
path.heroArmy = node.actor->creatureSet;
|
||||
path.armyLoss = node.armyLoss;
|
||||
path.targetObjectDanger = evaluateDanger(pos, path.targetHero);
|
||||
path.chainMask = node.actor->chainMask;
|
||||
|
||||
fillChainInfo(&node, path);
|
||||
|
||||
@@ -551,22 +609,26 @@ void AINodeStorage::fillChainInfo(const AIPathNode * node, AIPath & path) const
|
||||
{
|
||||
while(node != nullptr)
|
||||
{
|
||||
if(!node->actor->hero || node->coord == node->actor->hero->visitablePos())
|
||||
if(!node->actor->hero)
|
||||
return;
|
||||
|
||||
AIPathNodeInfo pathNode;
|
||||
pathNode.cost = node->cost;
|
||||
pathNode.targetHero = node->actor->hero;
|
||||
pathNode.turns = node->turns;
|
||||
pathNode.danger = node->danger;
|
||||
pathNode.coord = node->coord;
|
||||
|
||||
path.nodes.push_back(pathNode);
|
||||
path.specialAction = node->specialAction;
|
||||
|
||||
if(node->chainOther)
|
||||
fillChainInfo(node->chainOther, path);
|
||||
|
||||
if(node->actor->hero->visitablePos() != node->coord)
|
||||
{
|
||||
AIPathNodeInfo pathNode;
|
||||
pathNode.cost = node->cost;
|
||||
pathNode.targetHero = node->actor->hero;
|
||||
pathNode.turns = node->turns;
|
||||
pathNode.danger = node->danger;
|
||||
pathNode.coord = node->coord;
|
||||
|
||||
path.nodes.push_back(pathNode);
|
||||
}
|
||||
|
||||
path.specialAction = node->specialAction;
|
||||
|
||||
node = getAINode(node->theNodeBefore);
|
||||
}
|
||||
}
|
||||
@@ -586,6 +648,11 @@ int3 AIPath::firstTileToGet() const
|
||||
return int3(-1, -1, -1);
|
||||
}
|
||||
|
||||
const AIPathNodeInfo & AIPath::firstNode() const
|
||||
{
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
uint64_t AIPath::getPathDanger() const
|
||||
{
|
||||
if(nodes.size())
|
||||
|
||||
Reference in New Issue
Block a user