1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00
This commit is contained in:
Michał W. Urbańczyk 2012-04-14 07:22:08 +00:00
parent 722ec55384
commit b5526f0f54
3 changed files with 60 additions and 45 deletions

View File

@ -41,6 +41,24 @@ struct SetGlobalState
}
};
template <typename Container>
typename Container::value_type backOrNull(const Container &c) //returns last element of container or NULL if it is empty (to be used with containers of pointers)
{
if(c.size())
return c.back();
else
return NULL;
}
template <typename Container>
typename Container::value_type frontOrNull(const Container &c) //returns first element of container or NULL if it is empty (to be used with containers of pointers)
{
if(c.size())
return c.front();
else
return NULL;
}
#define SET_GLOBAL_STATE(ai) SetGlobalState _hlpSetState(ai);
#define NET_EVENT_HANDLER SET_GLOBAL_STATE(this)
@ -294,8 +312,9 @@ ui64 evaluateDanger(crint3 tile)
ui64 objectDanger = 0, guardDanger = 0;
if(t->visitable)
objectDanger = evaluateDanger(t->visitableObjects.back());
auto visObjs = cb->getVisitableObjs(tile);
if(visObjs.size())
objectDanger = evaluateDanger(visObjs.back());
int3 guardPos = cb->guardingCreaturePosition(tile);
if(guardPos.x >= 0 && guardPos != tile)
@ -314,15 +333,14 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
return 190000000; //MUCH
ui64 objectDanger = 0, guardDanger = 0;
CArmedInstance * dangerousObject;
if(t->visitable)
if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
{
dangerousObject = dynamic_cast<CArmedInstance*>(t->visitableObjects.back());
objectDanger = evaluateDanger(t->visitableObjects.back()); //unguarded objects can also be dangerous or unhandled
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
if (dangerousObject)
{
objectDanger *= fh->getTacticalAdvantage (visitor, dangerousObject);
//TODO: don't downcast objects AI shouldnt know about!
objectDanger *= fh->getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance*>(dangerousObject));
}
}
@ -410,22 +428,17 @@ void VCAI::heroMoved(const TryMoveHero & details)
LOG_ENTRY;
if(details.result == TryMoveHero::TELEPORTATION)
{
const TerrainTile *t1 = cb->getTile(CGHeroInstance::convertPosition(details.start, false), false),
*t2 = cb->getTile(CGHeroInstance::convertPosition(details.end, false), false);
if(!t1 || !t2) //enemy may have teleported to a tile we don't see
return;
if(t1->visitable && t2->visitable)
const int3 from = CGHeroInstance::convertPosition(details.start, false),
to = CGHeroInstance::convertPosition(details.end, false);
const CGObjectInstance *o1 = frontOrNull(cb->getVisitableObjs(from)),
*o2 = frontOrNull(cb->getVisitableObjs(to));
if(o1 && o2 && o1->ID == Obj::SUBTERRANEAN_GATE && o2->ID == Obj::SUBTERRANEAN_GATE)
{
const CGObjectInstance *o1 = t1->visitableObjects.front(),
*o2 = t2->visitableObjects.front();
if(o1->ID == Obj::SUBTERRANEAN_GATE && o2->ID == Obj::SUBTERRANEAN_GATE)
{
knownSubterraneanGates[o1] = o2;
knownSubterraneanGates[o2] = o1;
}
knownSubterraneanGates[o1] = o2;
knownSubterraneanGates[o2] = o1;
BNLOG("Found a pair of subterranean gates between %s and %s!", from % to);
}
}
}
@ -1225,8 +1238,8 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
{
assert(playerID > GameConstants::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
status.setBattle(ONGOING_BATTLE);
const TerrainTile *t = myCb->getTile(tile); //may be NULL in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
battlename = boost::str(boost::format("battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (t ? t->visitableObjects.back()->hoverName : "unknown enemy") % tile);
const CGObjectInstance *presumedEnemy = backOrNull(cb->getVisitableObjs(tile)); //may be NULL in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->hoverName : "unknown enemy") % tile);
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
}
@ -1278,17 +1291,14 @@ void VCAI::validateVisitableObjs()
void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
{
for(int i = 0; i < cb->getMapSize().x; i++)
for(int j = 0; j < cb->getMapSize().y; j++)
for(int k = 0; k < cb->getMapSize().z; k++)
if(const TerrainTile *t = cb->getTile(int3(i,j,k), false))
{
BOOST_FOREACH(const CGObjectInstance *obj, t->visitableObjects)
{
if(includeOwned || obj->tempOwner != playerID)
out.push_back(obj);
}
}
foreach_tile_pos([&](const int3 &pos)
{
BOOST_FOREACH(const CGObjectInstance *obj, cb->getVisitableObjs(pos, false))
{
if(includeOwned || obj->tempOwner != playerID)
out.push_back(obj);
}
});
}
std::vector<const CGObjectInstance *> VCAI::getFlaggedObjects() const
@ -1384,7 +1394,7 @@ bool VCAI::moveHeroToTile(int3 dst, const CGHeroInstance * h)
bool ret = false;
if(startHpos == dst)
{
assert(cb->getTile(dst)->visitableObjects.size() > 1); //there's no point in revisiting tile where there is no visitable object
assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
cb->moveHero(h,CGHeroInstance::convertPosition(dst, true));
waitTillFree(); //movement may cause battle or blocking dialog
ret = true;
@ -2263,10 +2273,10 @@ TSubgoal CGoal::whatToDoToAchieve()
case DIG_AT_TILE:
{
auto objs = cb->getTile(tile)->visitableObjects;
if(objs.size() && objs.front()->ID == GameConstants::HEROI_TYPE && objs.front()->tempOwner == ai->playerID) //we have hero at dest
const CGObjectInstance *firstObj = frontOrNull(cb->getVisitableObjs(tile));
if(firstObj && firstObj->ID == GameConstants::HEROI_TYPE && firstObj->tempOwner == ai->playerID) //we have hero at dest
{
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(objs.front());
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj);
return CGoal(*this).sethero(h).setisElementar(true);
}
@ -2332,7 +2342,9 @@ TSubgoal CGoal::whatToDoToAchieve()
if(howManyCanWeBuy + cb->getResourceAmount(resID) >= value)
{
if(cb->getTile(m->o->visitablePos())->visitableObjects.back()->tempOwner != ai->playerID)
auto backObj = backOrNull(cb->getVisitableObjs(m->o->visitablePos())); //it'll be a hero if we have one there; otherwise marketplace
assert(backObj);
if(backObj->tempOwner != ai->playerID)
return CGoal(GET_OBJ).setobjid(m->o->id);
return setobjid(m->o->id).setisElementar(true);
}

View File

@ -861,15 +861,18 @@ std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int
return ret;
}
std::vector < const CGObjectInstance * > CGameInfoCallback::getVisitableObjs( int3 pos ) const
std::vector <const CGObjectInstance * > CGameInfoCallback::getVisitableObjs(int3 pos, bool verbose /*= true*/) const
{
std::vector<const CGObjectInstance *> ret;
const TerrainTile *t = getTile(pos);
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
const TerrainTile *t = getTile(pos, verbose);
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret);
BOOST_FOREACH(const CGObjectInstance * obj, t->visitableObjects)
ret.push_back(obj);
{
if(player < 0 || obj->ID != GameConstants::EVENTI_TYPE) //hide events from players
ret.push_back(obj);
}
return ret;
}

View File

@ -185,7 +185,7 @@ public:
//objects
const CGObjectInstance* getObj(int objid, bool verbose = true) const;
std::vector <const CGObjectInstance * > getBlockingObjs(int3 pos)const;
std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos)const;
std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true)const;
std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
int getOwner(int heroID) const;