1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-23 12:08:45 +02:00

-Fixed crash

-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

@ -80,6 +80,8 @@ std::string goalName(EGoals goalType)
return "INVALID"; return "INVALID";
case WIN: case WIN:
return "WIN"; return "WIN";
case DO_NOT_LOSE:
return "DO NOT LOOSE";
case CONQUER: case CONQUER:
return "CONQUER"; return "CONQUER";
case BUILD: case BUILD:
@ -88,10 +90,26 @@ std::string goalName(EGoals goalType)
return "EXPLORE"; return "EXPLORE";
case GATHER_ARMY: case GATHER_ARMY:
return "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: case VISIT_TILE:
return "VISIT TILE"; return "VISIT TILE";
case CLEAR_WAY_TO: case CLEAR_WAY_TO:
return "CLEAR WAY TO"; return "CLEAR WAY TO";
case DIG_AT_TILE:
return "DIG AT TILE";
default: default:
return boost::lexical_cast<std::string>(goalType); 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); cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive);
if(cb->getResourceAmount(g.resID) >= g.value) if(cb->getResourceAmount(g.resID) >= g.value)
return; return;
} } //TODO: stop when we've sold all the resources
} }
else else
{ {
@ -2064,7 +2082,7 @@ void VCAI::striveToQuest (const QuestInfo &q)
{ {
MetaString ms; MetaString ms;
q.quest->getRolloverText(ms, false); 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) switch (q.quest->missionType)
{ {
case CQuest::MISSION_ART: case CQuest::MISSION_ART:
@ -2111,7 +2129,11 @@ void VCAI::striveToQuest (const QuestInfo &q)
case CQuest::MISSION_KILL_HERO: case CQuest::MISSION_KILL_HERO:
case CQuest::MISSION_KILL_CREATURE: 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; break;
} }
case CQuest::MISSION_PRIMARY_STAT: case CQuest::MISSION_PRIMARY_STAT:
@ -2153,7 +2175,7 @@ void VCAI::striveToQuest (const QuestInfo &q)
} }
case CQuest::MISSION_KEYMASTER: 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; break;
} }
} }
@ -2246,7 +2268,7 @@ int3 VCAI::explorationNewPoint(int radius, HeroPtr h, std::vector<std::vector<in
BOOST_FOREACH(const int3 &tile, tiles[i]) 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; return tile;
} }
@ -2657,12 +2679,14 @@ TSubgoal CGoal::whatToDoToAchieve()
} }
} }
else else
BOOST_FOREACH(const CGObjectInstance *obj, ai->visitableObjs)
{ {
if(obj->ID == objid) BOOST_FOREACH(const CGObjectInstance *obj, ai->visitableObjs)
{ {
o = obj; if(obj->ID == objid)
break; //TODO: consider multiple objects and choose best {
o = obj;
break; //TODO: consider multiple objects and choose best
}
} }
} }
if (o) if (o)
@ -2714,6 +2738,8 @@ TSubgoal CGoal::whatToDoToAchieve()
return CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(cb->getTile(tileToHit)->visitableObjects.back()->subID); return CGoal(FIND_OBJ).setobjid(Obj::KEYMASTER).setresID(cb->getTile(tileToHit)->visitableObjects.back()->subID);
} }
//FIXME: this code shouldn't be necessary
if(tileToHit == tile) 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") 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; return goalType == INVALID;
} }
bool CGoal::isBlockedBorderGate(int3 tileToHit) bool isBlockedBorderGate(int3 tileToHit)
{ {
return cb->getTile(tileToHit)->topVisitableID() == Obj::BORDER_GATE return cb->getTile(tileToHit)->topVisitableID() == Obj::BORDER_GATE
&& cb->getPathInfo(tileToHit)->accessible != CGPathNode::ACCESSIBLE; && cb->getPathInfo(tileToHit)->accessible != CGPathNode::ACCESSIBLE;
@ -3199,20 +3225,22 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{ {
switch (obj->ID) switch (obj->ID)
{ {
case Obj::BORDERGUARD:
case Obj::BORDER_GATE:
case Obj::SEER_HUT: case Obj::SEER_HUT:
case Obj::QUEST_GUARD:
{ {
BOOST_FOREACH (auto q, ai->myCb->getMyQuests()) BOOST_FOREACH (auto q, ai->myCb->getMyQuests())
{ {
if (q.obj = obj) if (q.obj == obj)
{ {
if (q.quest->checkQuest(*h)) if (q.quest->checkQuest(*h))
return true; //we completed the quest return true; //we completed the quest
else else
return false; //we can't complete this quest 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: case Obj::CREATURE_GENERATOR1:
{ {

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

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

@ -1468,6 +1468,19 @@ void CGameState::init(StartInfo * si)
if(obj->ID == 62) //prison also needs to initialize hero if(obj->ID == 62) //prison also needs to initialize hero
static_cast<CGHeroInstance*>(obj)->initHero(); 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 CGTeleport::postInit(); //pairing subterranean gates
buildBonusSystemTree(); buildBonusSystemTree();

@ -4399,6 +4399,20 @@ void CQuest::getCompletionText (MetaString &iwText, std::vector<Component> &comp
break; 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() void CGSeerHut::initObj()
{ {
@ -4413,17 +4427,6 @@ void CGSeerHut::initObj()
nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption]; nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption];
if (!isCustomComplete) if (!isCustomComplete)
completedText = VLC->generaltexth->quests[missionType-1][2][textOption]; 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 else
firstVisitText = VLC->generaltexth->seerEmpty[textOption]; 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]; 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 void CGBorderGuard::onHeroVisit( const CGHeroInstance * h ) const
{ {
if (wasMyColorVisited (h->getOwner()) ) if (wasMyColorVisited (h->getOwner()) )

@ -82,7 +82,7 @@ public:
std::string firstVisitText, nextVisitText, completedText; std::string firstVisitText, nextVisitText, completedText;
bool isCustomFirst, isCustomNext, isCustomComplete; 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 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 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 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 finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects
void completeQuest (const CGHeroInstance * h) const; 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 CGHeroInstance *getHeroToKill(bool allowNull = false) const;
const CGCreature *getCreatureToKill(bool allowNull = false) const; const CGCreature *getCreatureToKill(bool allowNull = false) const;
@ -1077,6 +1078,7 @@ public:
const std::string & getHoverText() const; const std::string & getHoverText() const;
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = NULL) 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; void getRolloverText (MetaString &text, bool onHover) const;
bool checkQuest (const CGHeroInstance * h) const;
void onHeroVisit(const CGHeroInstance * h) const; void onHeroVisit(const CGHeroInstance * h) const;
void openGate(const CGHeroInstance *h, ui32 accept) const; void openGate(const CGHeroInstance *h, ui32 accept) const;

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

@ -308,11 +308,24 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
return; return;
} }
// else if (obj->ID==CREI_TYPE && gs->map->version > CMapHeader::RoE) //only fixed monsters can be a part of quest //FIXME: for some reason this code causes crash in Bonus System ?!
// {
// CGCreature *cre = static_cast<CGCreature*>(obj); auto quest = dynamic_cast<const CQuest *>(obj);
// gs->map->monsters[cre->identifier]->pos = int3 (-1,-1,-1); //use nonexistent monster for quest :> 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(); gs->map->objects[id].dellNull();
} }
@ -1495,7 +1508,7 @@ DLL_LINKAGE void SetSelection::applyGs( CGameState *gs )
} }
DLL_LINKAGE Component::Component(const CStackBasicDescriptor &stack) 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;
} }