mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Handling for Hill fort and (kinda) Magic Well
- Improved hero exchange - Fixed strange case when AI found allied town extremely dangerous, resulting in endless loop
This commit is contained in:
parent
8fac276922
commit
4e726f0eb2
@ -100,6 +100,8 @@ std::string goalName(EGoals goalType)
|
|||||||
return "GET OBJECT";
|
return "GET OBJECT";
|
||||||
case FIND_OBJ:
|
case FIND_OBJ:
|
||||||
return "FIND OBJECT";
|
return "FIND OBJECT";
|
||||||
|
case VISIT_HERO:
|
||||||
|
return "VISIT HERO";
|
||||||
case GET_ART_TYPE:
|
case GET_ART_TYPE:
|
||||||
return "GET ARTIFACT OF TYPE";
|
return "GET ARTIFACT OF TYPE";
|
||||||
case ISSUE_COMMAND:
|
case ISSUE_COMMAND:
|
||||||
@ -359,12 +361,12 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
|
|||||||
if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
|
if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
|
||||||
{
|
{
|
||||||
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
||||||
if (dangerousObject)
|
if (objectDanger)
|
||||||
{
|
{
|
||||||
//TODO: don't downcast objects AI shouldnt know about!
|
//TODO: don't downcast objects AI shouldnt know about!
|
||||||
auto armedObj = dynamic_cast<const CArmedInstance*>(dangerousObject);
|
auto armedObj = dynamic_cast<const CArmedInstance*>(dangerousObject);
|
||||||
if(armedObj)
|
if(armedObj)
|
||||||
objectDanger *= fh->getTacticalAdvantage(visitor, armedObj);
|
objectDanger *= fh->getTacticalAdvantage(visitor, armedObj); //this line tends to go infinite for allied towns (?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,8 +376,6 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
|
|||||||
|
|
||||||
//TODO mozna odwiedzic blockvis nie ruszajac straznika
|
//TODO mozna odwiedzic blockvis nie ruszajac straznika
|
||||||
return std::max(objectDanger, guardDanger);
|
return std::max(objectDanger, guardDanger);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui64 evaluateDanger(const CGObjectInstance *obj)
|
ui64 evaluateDanger(const CGObjectInstance *obj)
|
||||||
@ -647,9 +647,9 @@ void VCAI::heroExchangeStarted(si32 hero1, si32 hero2)
|
|||||||
|
|
||||||
requestActionASAP([=]()
|
requestActionASAP([=]()
|
||||||
{
|
{
|
||||||
if (firstHero->getHeroStrength() > secondHero->getHeroStrength())
|
if (firstHero->getHeroStrength() > secondHero->getHeroStrength() && canGetArmy (firstHero, secondHero))
|
||||||
pickBestCreatures (firstHero, secondHero);
|
pickBestCreatures (firstHero, secondHero);
|
||||||
else
|
else if (canGetArmy (secondHero, firstHero))
|
||||||
pickBestCreatures (secondHero, firstHero);
|
pickBestCreatures (secondHero, firstHero);
|
||||||
|
|
||||||
completeGoal(CGoal(VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime?
|
completeGoal(CGoal(VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime?
|
||||||
@ -721,6 +721,11 @@ void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstan
|
|||||||
{
|
{
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
LOG_ENTRY;
|
LOG_ENTRY;
|
||||||
|
|
||||||
|
requestActionASAP([=]()
|
||||||
|
{
|
||||||
|
makePossibleUpgrades(visitor);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::playerBonusChanged(const Bonus &bonus, bool gain)
|
void VCAI::playerBonusChanged(const Bonus &bonus, bool gain)
|
||||||
@ -1111,6 +1116,36 @@ void VCAI::moveCreaturesToHero(const CGTownInstance * t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VCAI::canGetArmy (const CGHeroInstance * h, const CGHeroInstance * source)
|
||||||
|
{
|
||||||
|
int totalStacks = h->Slots().size() + source->Slots().size();
|
||||||
|
if (totalStacks > GameConstants::ARMY_SIZE)
|
||||||
|
{ //exchange stacks or move full stack
|
||||||
|
BOOST_FOREACH (auto slot, source->Slots())
|
||||||
|
{
|
||||||
|
if (h->getSlotFor(slot.second->type->idNumber)) //we can take full stack
|
||||||
|
return true;
|
||||||
|
BOOST_FOREACH (auto ourSlot, h->Slots())
|
||||||
|
{
|
||||||
|
if (slot.second->getPower() > ourSlot.second->getPower())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //only exchange
|
||||||
|
{
|
||||||
|
BOOST_FOREACH (auto slot, source->Slots())
|
||||||
|
{
|
||||||
|
BOOST_FOREACH (auto ourSlot, h->Slots())
|
||||||
|
{
|
||||||
|
if (slot.second->getPower() > ourSlot.second->getPower())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source)
|
void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source)
|
||||||
{
|
{
|
||||||
//TODO - what if source is a hero (the last stack problem) -> it'd good to create a single stack of weakest cre
|
//TODO - what if source is a hero (the last stack problem) -> it'd good to create a single stack of weakest cre
|
||||||
@ -1138,10 +1173,16 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
|
|||||||
|
|
||||||
//foreach best type -> iterate over slots in both armies and if it's the appropriate type, send it to the slot where it belongs
|
//foreach best type -> iterate over slots in both armies and if it's the appropriate type, send it to the slot where it belongs
|
||||||
for (int i = 0; i < bestArmy.size(); i++) //i-th strongest creature type will go to i-th slot
|
for (int i = 0; i < bestArmy.size(); i++) //i-th strongest creature type will go to i-th slot
|
||||||
|
{
|
||||||
|
if (source->needsLastStack() && source->Slots().size() <= 1)
|
||||||
|
break;
|
||||||
BOOST_FOREACH(auto armyPtr, armies)
|
BOOST_FOREACH(auto armyPtr, armies)
|
||||||
for (int j = 0; j < GameConstants::ARMY_SIZE; j++)
|
for (int j = 0; j < GameConstants::ARMY_SIZE; j++)
|
||||||
|
{
|
||||||
if(armyPtr->getCreature(j) == bestArmy[i] && (i != j || armyPtr != army)) //it's a searched creature not in dst slot
|
if(armyPtr->getCreature(j) == bestArmy[i] && (i != j || armyPtr != army)) //it's a searched creature not in dst slot
|
||||||
cb->mergeOrSwapStacks(armyPtr, army, j, i);
|
cb->mergeOrSwapStacks(armyPtr, army, j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO - having now strongest possible army, we may want to think about arranging stacks
|
//TODO - having now strongest possible army, we may want to think about arranging stacks
|
||||||
|
|
||||||
@ -3162,7 +3203,7 @@ TSubgoal CGoal::whatToDoToAchieve()
|
|||||||
auto heroDummy = hero;
|
auto heroDummy = hero;
|
||||||
erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
|
erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
|
||||||
{
|
{
|
||||||
return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->pos, h, true));
|
return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->pos, h, true) || !ai->canGetArmy(heroDummy.h, h));
|
||||||
});
|
});
|
||||||
if (otherHeroes.size())
|
if (otherHeroes.size())
|
||||||
{
|
{
|
||||||
@ -3375,8 +3416,11 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
|
|||||||
return true;
|
return true;
|
||||||
switch (obj->ID)
|
switch (obj->ID)
|
||||||
{
|
{
|
||||||
case Obj::STABLES: //any other potential visitable objects?
|
case Obj::STABLES:
|
||||||
|
case Obj::MAGIC_WELL:
|
||||||
|
case Obj::HILL_FORT:
|
||||||
return true;
|
return true;
|
||||||
|
break;
|
||||||
case Obj::BORDER_GATE:
|
case Obj::BORDER_GATE:
|
||||||
case Obj::BORDERGUARD:
|
case Obj::BORDERGUARD:
|
||||||
return (dynamic_cast <const CGKeys *>(obj))->wasMyColorVisited (ai->playerID); //FIXME: they could be revisited sooner than in a week
|
return (dynamic_cast <const CGKeys *>(obj))->wasMyColorVisited (ai->playerID); //FIXME: they could be revisited sooner than in a week
|
||||||
@ -3425,6 +3469,16 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
|||||||
return canRecruitCreatures;
|
return canRecruitCreatures;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Obj::HILL_FORT:
|
||||||
|
{
|
||||||
|
BOOST_FOREACH (auto slot, h->Slots())
|
||||||
|
{
|
||||||
|
if (slot.second->type->upgrades.size())
|
||||||
|
return true; //TODO: check price?
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Obj::MONOLITH1:
|
case Obj::MONOLITH1:
|
||||||
case Obj::MONOLITH2:
|
case Obj::MONOLITH2:
|
||||||
case Obj::MONOLITH3:
|
case Obj::MONOLITH3:
|
||||||
@ -3451,6 +3505,9 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Obj::MAGIC_WELL:
|
||||||
|
return h->mana < h->manaLimit();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->wasVisited(*h)) //it must pointer to hero instance, heroPtr calls function wasVisited(ui8 player);
|
if (obj->wasVisited(*h)) //it must pointer to hero instance, heroPtr calls function wasVisited(ui8 player);
|
||||||
|
@ -327,6 +327,7 @@ public:
|
|||||||
void buildStructure(const CGTownInstance * t);
|
void buildStructure(const CGTownInstance * t);
|
||||||
//void recruitCreatures(const CGTownInstance * t);
|
//void recruitCreatures(const CGTownInstance * t);
|
||||||
void recruitCreatures(const CGDwelling * d);
|
void recruitCreatures(const CGDwelling * d);
|
||||||
|
bool canGetArmy (const CGHeroInstance * h, const CGHeroInstance * source); //can we get any better stacks from other hero?
|
||||||
void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
|
void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
|
||||||
void moveCreaturesToHero(const CGTownInstance * t);
|
void moveCreaturesToHero(const CGTownInstance * t);
|
||||||
bool goVisitObj(const CGObjectInstance * obj, HeroPtr h);
|
bool goVisitObj(const CGObjectInstance * obj, HeroPtr h);
|
||||||
@ -375,4 +376,6 @@ bool objWithID(const CGObjectInstance *obj)
|
|||||||
bool isBlockedBorderGate(int3 tileToHit);
|
bool isBlockedBorderGate(int3 tileToHit);
|
||||||
|
|
||||||
bool isWeeklyRevisitable (const CGObjectInstance * obj);
|
bool isWeeklyRevisitable (const CGObjectInstance * obj);
|
||||||
bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);
|
bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);
|
||||||
|
|
||||||
|
void makePossibleUpgrades(const CArmedInstance *obj);
|
@ -210,12 +210,14 @@ namespace Obj
|
|||||||
DERELICT_SHIP = 24,
|
DERELICT_SHIP = 24,
|
||||||
DRAGON_UTOPIA = 25,
|
DRAGON_UTOPIA = 25,
|
||||||
GARRISON = 33,
|
GARRISON = 33,
|
||||||
|
HILL_FORT = 35,
|
||||||
LIBRARY_OF_ENLIGHTENMENT = 41,
|
LIBRARY_OF_ENLIGHTENMENT = 41,
|
||||||
MONOLITH1 = 43,
|
MONOLITH1 = 43,
|
||||||
MONOLITH2 = 44,
|
MONOLITH2 = 44,
|
||||||
MONOLITH3 = 45,
|
MONOLITH3 = 45,
|
||||||
MAGIC_PLAINS1 = 46,
|
MAGIC_PLAINS1 = 46,
|
||||||
SCHOOL_OF_MAGIC = 47,
|
SCHOOL_OF_MAGIC = 47,
|
||||||
|
MAGIC_WELL = 49,
|
||||||
MINE = 53,
|
MINE = 53,
|
||||||
MONSTER = 54,
|
MONSTER = 54,
|
||||||
OBELISK = 57,
|
OBELISK = 57,
|
||||||
|
Loading…
Reference in New Issue
Block a user