1
0
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:
DjWarmonger 2012-08-29 09:19:20 +00:00
parent 8fac276922
commit 4e726f0eb2
3 changed files with 72 additions and 10 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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,