1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

-Fixed crash #1037

-AI can now successfully complete several types of quests.
-Lots of tweaks for AI
TODO: fix bizarre crash when opening borderguard
This commit is contained in:
DjWarmonger 2012-07-19 09:10:55 +00:00
parent 6a7327d38a
commit d8cb3a34d3
8 changed files with 99 additions and 33 deletions

View File

@ -80,6 +80,8 @@ std::string goalName(EGoals goalType)
return "INVALID";
case WIN:
return "WIN";
case DO_NOT_LOSE:
return "DO NOT LOOSE";
case CONQUER:
return "CONQUER";
case BUILD:
@ -88,10 +90,26 @@ std::string goalName(EGoals goalType)
return "EXPLORE";
case GATHER_ARMY:
return "GATHER ARMY";
case BOOST_HERO:
return "BOOST_HERO (unsupported)";
case BUILD_STRUCTURE:
return "BUILD STRUCTURE";
case COLLECT_RES:
return "COLLECT RESOURCE";
case GET_OBJ:
return "GET OBJECT";
case FIND_OBJ:
return "FIND OBJECT";
case GET_ART_TYPE:
return "GET ARTIFACT OF TYPE";
case ISSUE_COMMAND:
return "ISSUE COMMAND (unsupported)";
case VISIT_TILE:
return "VISIT TILE";
case CLEAR_WAY_TO:
return "CLEAR WAY TO";
case DIG_AT_TILE:
return "DIG AT TILE";
default:
return boost::lexical_cast<std::string>(goalType);
}
@ -1851,7 +1869,7 @@ void VCAI::tryRealize(CGoal g)
cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive);
if(cb->getResourceAmount(g.resID) >= g.value)
return;
}
} //TODO: stop when we've sold all the resources
}
else
{
@ -2064,7 +2082,7 @@ void VCAI::striveToQuest (const QuestInfo &q)
{
MetaString ms;
q.quest->getRolloverText(ms, false);
BNLOG ("Trying to realize quest: %s\n", ms.toString());
BNLOG ("Trying to realize quest: %s", ms.toString());
switch (q.quest->missionType)
{
case CQuest::MISSION_ART:
@ -2111,7 +2129,11 @@ void VCAI::striveToQuest (const QuestInfo &q)
case CQuest::MISSION_KILL_HERO:
case CQuest::MISSION_KILL_CREATURE:
{
striveToGoal (CGoal(GET_OBJ).setobjid(q.quest->m13489val));
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
if (obj)
striveToGoal (CGoal(GET_OBJ).setobjid(obj->id));
else
striveToGoal (CGoal(VISIT_TILE).settile(q.tile)); //visit seer hut
break;
}
case CQuest::MISSION_PRIMARY_STAT:
@ -2153,7 +2175,7 @@ void VCAI::striveToQuest (const QuestInfo &q)
}
case CQuest::MISSION_KEYMASTER:
{
striveToGoal (CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(q.quest->m13489val));
striveToGoal (CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(q.obj->subID));
break;
}
}
@ -2246,7 +2268,7 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<in
BOOST_FOREACH(const int3 &tile, tiles[i])
{
if(cb->getPathInfo(tile)->reachable() && isSafeToVisit(h, tile) && howManyTilesWillBeDiscovered(tile, radius))
if(cb->getPathInfo(tile)->reachable() && isSafeToVisit(h, tile) && howManyTilesWillBeDiscovered(tile, radius) && !isBlockedBorderGate(tile))
{
return tile;
}
@ -2657,12 +2679,14 @@ TSubgoal CGoal::whatToDoToAchieve()
}
}
else
BOOST_FOREACH(const CGObjectInstance *obj, ai->visitableObjs)
{
if(obj->ID == objid)
BOOST_FOREACH(const CGObjectInstance *obj, ai->visitableObjs)
{
o = obj;
break; //TODO: consider multiple objects and choose best
if(obj->ID == objid)
{
o = obj;
break; //TODO: consider multiple objects and choose best
}
}
}
if (o)
@ -2714,6 +2738,8 @@ TSubgoal CGoal::whatToDoToAchieve()
return CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(cb->getTile(tileToHit)->visitableObjects.back()->subID);
}
//FIXME: this code shouldn't be necessary
if(tileToHit == tile)
{
tlog1 << boost::format("Very strange, tile to hit is %s and tile is also %s, while hero %s is at %s\n")
@ -3052,7 +3078,7 @@ bool CGoal::invalid() const
return goalType == INVALID;
}
bool CGoal::isBlockedBorderGate(int3 tileToHit)
bool isBlockedBorderGate(int3 tileToHit)
{
return cb->getTile(tileToHit)->topVisitableID() == Obj::BORDER_GATE
&& cb->getPathInfo(tileToHit)->accessible != CGPathNode::ACCESSIBLE;
@ -3199,20 +3225,22 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{
switch (obj->ID)
{
case Obj::BORDERGUARD:
case Obj::BORDER_GATE:
case Obj::SEER_HUT:
case Obj::QUEST_GUARD:
{
BOOST_FOREACH (auto q, ai->myCb->getMyQuests())
{
if (q.obj = obj)
if (q.obj == obj)
{
if (q.quest->checkQuest(*h))
return true; //we completed the quest
else
return false; //we can't complete this quest
}
return true; //we don't have this quest yet
}
return true; //we don't have this quest yet
}
case Obj::CREATURE_GENERATOR1:
{

View File

@ -110,7 +110,6 @@ struct CGoal
virtual TSubgoal whatToDoToAchieve();
bool isBlockedBorderGate(int3 tileToHit);
CGoal(EGoals goal = INVALID) : goalType(goal)
{
priority = 0;
@ -374,6 +373,7 @@ bool objWithID(const CGObjectInstance *obj)
{
return obj->ID == id;
}
bool isBlockedBorderGate(int3 tileToHit);
bool isWeeklyRevisitable (const CGObjectInstance * obj);
bool shouldVisit (HeroPtr h, const CGObjectInstance * obj);

View File

@ -318,6 +318,7 @@ void UpdateCampaignState::applyCl( CClient *cl )
void RemoveObject::applyFirstCl( CClient *cl )
{
const CGObjectInstance *o = cl->getObj(id);
CGI->mh->hideObject(o);
int3 pos = o->visitablePos();

View File

@ -1468,6 +1468,19 @@ void CGameState::init(StartInfo * si)
if(obj->ID == 62) //prison also needs to initialize hero
static_cast<CGHeroInstance*>(obj)->initHero();
}
BOOST_FOREACH(CGObjectInstance *obj, map->objects)
{
switch (obj->ID)
{
case Obj::QUEST_GUARD:
case Obj::SEER_HUT:
{
auto q = static_cast<CGSeerHut*>(obj);
assert (q);
q->setObjToKill();
}
}
}
CGTeleport::postInit(); //pairing subterranean gates
buildBonusSystemTree();

View File

@ -4399,6 +4399,20 @@ void CQuest::getCompletionText (MetaString &iwText, std::vector<Component> &comp
break;
}
}
void CGSeerHut::setObjToKill()
{
if (missionType == MISSION_KILL_CREATURE)
{
stackToKill = getCreatureToKill(false)->getStack(0); //FIXME: stacks tend to dissapear (desync?) on server :?
assert (stackToKill.count > 0); //seemingly creatures are uninitialized
stackDirection = checkDirection();
}
else if (missionType == MISSION_KILL_HERO)
{
heroName = getHeroToKill(false)->name;
heroPortrait = getHeroToKill(false)->portrait;
}
}
void CGSeerHut::initObj()
{
@ -4413,17 +4427,6 @@ void CGSeerHut::initObj()
nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption];
if (!isCustomComplete)
completedText = VLC->generaltexth->quests[missionType-1][2][textOption];
if(missionType == MISSION_KILL_CREATURE)
{
stackToKill = getCreatureToKill(false)->getStack(0);
stackDirection = checkDirection();
}
else if(missionType == MISSION_KILL_HERO)
{
heroName = getHeroToKill(false)->name;
heroPortrait = getHeroToKill(false)->portrait;
}
}
else
firstVisitText = VLC->generaltexth->seerEmpty[textOption];
@ -6326,6 +6329,11 @@ void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const
text << VLC->generaltexth->tentColors[subID] << " " << VLC->generaltexth->names[Obj::KEYMASTER];
}
bool CGBorderGuard::checkQuest (const CGHeroInstance * h) const
{
return wasMyColorVisited (h->tempOwner);
}
void CGBorderGuard::onHeroVisit( const CGHeroInstance * h ) const
{
if (wasMyColorVisited (h->getOwner()) )

View File

@ -82,7 +82,7 @@ public:
std::string firstVisitText, nextVisitText, completedText;
bool isCustomFirst, isCustomNext, isCustomComplete;
bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
virtual bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = NULL) const;
virtual void getCompletionText (MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h = NULL) const;
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
@ -782,6 +782,7 @@ public:
void finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects
void completeQuest (const CGHeroInstance * h) const;
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
const CGCreature *getCreatureToKill(bool allowNull = false) const;
@ -1077,6 +1078,7 @@ public:
const std::string & getHoverText() const;
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = NULL) const;
void getRolloverText (MetaString &text, bool onHover) const;
bool checkQuest (const CGHeroInstance * h) const;
void onHeroVisit(const CGHeroInstance * h) const;
void openGate(const CGHeroInstance *h, ui32 accept) const;

View File

@ -216,6 +216,7 @@ namespace Obj
SCHOOL_OF_WAR = 107,
WHIRLPOOL = 111,
BORDER_GATE = 212,
QUEST_GUARD = 215,
GARRISON2 = 219,
CLOVER_FIELD = 222,
CURSED_GROUND2 = 223,

View File

@ -308,11 +308,24 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
return;
}
// else if (obj->ID==CREI_TYPE && gs->map->version > CMapHeader::RoE) //only fixed monsters can be a part of quest
// {
// CGCreature *cre = static_cast<CGCreature*>(obj);
// gs->map->monsters[cre->identifier]->pos = int3 (-1,-1,-1); //use nonexistent monster for quest :>
// }
//FIXME: for some reason this code causes crash in Bonus System ?!
auto quest = dynamic_cast<const CQuest *>(obj);
if (quest)
{
BOOST_FOREACH (auto player, gs->players)
{
BOOST_FOREACH (auto q, player.second.quests)
{
if (q.obj == obj)
{
q.quest = NULL; //remove entries related to quest guards?
q.obj = NULL;
}
}
}
}
gs->map->objects[id].dellNull();
}
@ -1495,7 +1508,7 @@ DLL_LINKAGE void SetSelection::applyGs( CGameState *gs )
}
DLL_LINKAGE Component::Component(const CStackBasicDescriptor &stack)
:id(CREATURE), subtype(stack.type->idNumber), val(stack.count), when(0)
: id(CREATURE), subtype(stack.type->idNumber), val(stack.count), when(0)
{
type = 2002;
}