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:
parent
6a7327d38a
commit
d8cb3a34d3
@ -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:
|
||||
{
|
||||
|
@ -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);
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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()) )
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user