1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Quests now handled by pointers again, this time without bugs.

Fixed some issues with quests and AI.
This commit is contained in:
DjWarmonger
2012-10-03 14:49:29 +00:00
parent 977acfafc8
commit 4bacd97497
8 changed files with 143 additions and 117 deletions

View File

@@ -2057,6 +2057,15 @@ bool VCAI::fulfillsGoal (CGoal &goal, CGoal &mainGoal)
} }
return false; return false;
} }
bool VCAI::fulfillsGoal (CGoal &goal, const CGoal &mainGoal)
{
if (mainGoal.goalType == GET_OBJ && goal.goalType == VISIT_TILE) //deduce that GET_OBJ was completed by visiting object's tile
{ //TODO: more universal mechanism
if (cb->getObj(mainGoal.objid)->visitablePos() == goal.tile)
return true;
}
return false;
}
void VCAI::striveToGoal(const CGoal &ultimateGoal) void VCAI::striveToGoal(const CGoal &ultimateGoal)
{ {
@@ -2123,7 +2132,7 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
catch(goalFulfilledException &e) catch(goalFulfilledException &e)
{ {
completeGoal (goal); completeGoal (goal);
if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition if (fulfillsGoal (goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition
return; return;
} }
catch(std::exception &e) catch(std::exception &e)
@@ -2185,26 +2194,26 @@ void VCAI::striveToGoal(const CGoal &ultimateGoal)
void VCAI::striveToQuest (const QuestInfo &q) void VCAI::striveToQuest (const QuestInfo &q)
{ {
if (q.quest.missionType && q.quest.progress < CQuest::COMPLETE) //FIXME: quests are never synchronized. Pointer handling needed if (q.quest->missionType && q.quest->progress < CQuest::COMPLETE) //FIXME: quests are never synchronized. Pointer handling needed
{ {
MetaString ms; MetaString ms;
q.quest.getRolloverText(ms, false); q.quest->getRolloverText(ms, false);
BNLOG ("Trying to realize quest: %s", ms.toString()); BNLOG ("Trying to realize quest: %s", ms.toString());
auto heroes = cb->getHeroesInfo(); auto heroes = cb->getHeroesInfo();
switch (q.quest.missionType) switch (q.quest->missionType)
{ {
case CQuest::MISSION_ART: case CQuest::MISSION_ART:
{ {
BOOST_FOREACH (auto hero, heroes) //TODO: remove duplicated code? BOOST_FOREACH (auto hero, heroes) //TODO: remove duplicated code?
{ {
if (q.quest.checkQuest(hero)) if (q.quest->checkQuest(hero))
{ {
striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero)); striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero));
return; return;
} }
} }
BOOST_FOREACH (auto art, q.quest.m5arts) BOOST_FOREACH (auto art, q.quest->m5arts)
{ {
striveToGoal (CGoal(GET_ART_TYPE).setaid(art)); //TODO: transport? striveToGoal (CGoal(GET_ART_TYPE).setaid(art)); //TODO: transport?
} }
@@ -2215,7 +2224,7 @@ void VCAI::striveToQuest (const QuestInfo &q)
//striveToGoal (CGoal(RECRUIT_HERO)); //striveToGoal (CGoal(RECRUIT_HERO));
BOOST_FOREACH (auto hero, heroes) BOOST_FOREACH (auto hero, heroes)
{ {
if (q.quest.checkQuest(hero)) if (q.quest->checkQuest(hero))
{ {
striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero)); striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero));
return; return;
@@ -2229,13 +2238,13 @@ void VCAI::striveToQuest (const QuestInfo &q)
{ {
BOOST_FOREACH (auto hero, heroes) BOOST_FOREACH (auto hero, heroes)
{ {
if (q.quest.checkQuest(hero)) //veyr bad info - stacks can be split between multiple heroes :( if (q.quest->checkQuest(hero)) //veyr bad info - stacks can be split between multiple heroes :(
{ {
striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero)); striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero));
return; return;
} }
} }
BOOST_FOREACH (auto creature, q.quest.m6creatures) BOOST_FOREACH (auto creature, q.quest->m6creatures)
{ {
striveToGoal (CGoal(GATHER_TROOPS).setobjid(creature.type->idNumber).setvalue(creature.count)); striveToGoal (CGoal(GATHER_TROOPS).setobjid(creature.type->idNumber).setvalue(creature.count));
} }
@@ -2247,16 +2256,16 @@ void VCAI::striveToQuest (const QuestInfo &q)
{ {
if (heroes.size()) if (heroes.size())
{ {
if (q.quest.checkQuest(heroes.front())) //it doesn't matter which hero it is if (q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
{ {
striveToGoal (CGoal(VISIT_TILE).settile(q.tile)); striveToGoal (CGoal(VISIT_TILE).settile(q.tile));
} }
else else
{ {
for (int i = 0; i < q.quest.m7resources.size(); ++i) for (int i = 0; i < q.quest->m7resources.size(); ++i)
{ {
if (q.quest.m7resources[i]) if (q.quest->m7resources[i])
striveToGoal (CGoal(COLLECT_RES).setresID(i).setvalue(q.quest.m7resources[i])); striveToGoal (CGoal(COLLECT_RES).setresID(i).setvalue(q.quest->m7resources[i]));
} }
} }
} }
@@ -2267,7 +2276,7 @@ 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:
{ {
auto obj = cb->getObjByQuestIdentifier(q.quest.m13489val); auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
if (obj) if (obj)
striveToGoal (CGoal(GET_OBJ).setobjid(obj->id)); striveToGoal (CGoal(GET_OBJ).setobjid(obj->id));
else else
@@ -2279,13 +2288,13 @@ void VCAI::striveToQuest (const QuestInfo &q)
auto heroes = cb->getHeroesInfo(); auto heroes = cb->getHeroesInfo();
BOOST_FOREACH (auto hero, heroes) BOOST_FOREACH (auto hero, heroes)
{ {
if (q.quest.checkQuest(hero)) if (q.quest->checkQuest(hero))
{ {
striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero)); striveToGoal (CGoal(GET_OBJ).setobjid(q.obj->id).sethero(hero));
return; return;
} }
} }
for (int i = 0; i < q.quest.m2stats.size(); ++i) for (int i = 0; i < q.quest->m2stats.size(); ++i)
{ {
BNLOG ("Don't know how to increase primary stat %d\n", i); BNLOG ("Don't know how to increase primary stat %d\n", i);
} }
@@ -2296,19 +2305,19 @@ void VCAI::striveToQuest (const QuestInfo &q)
auto heroes = cb->getHeroesInfo(); auto heroes = cb->getHeroesInfo();
BOOST_FOREACH (auto hero, heroes) BOOST_FOREACH (auto hero, heroes)
{ {
if (q.quest.checkQuest(hero)) if (q.quest->checkQuest(hero))
{ {
striveToGoal (CGoal(VISIT_TILE).settile(q.tile).sethero(hero)); //TODO: causes infinite loop :/ striveToGoal (CGoal(VISIT_TILE).settile(q.tile).sethero(hero)); //TODO: causes infinite loop :/
return; return;
} }
} }
BNLOG ("Don't know how to reach hero level %d\n", q.quest.m13489val); BNLOG ("Don't know how to reach hero level %d\n", q.quest->m13489val);
break; break;
} }
case CQuest::MISSION_PLAYER: case CQuest::MISSION_PLAYER:
{ {
if (playerID != q.quest.m13489val) if (playerID != q.quest->m13489val)
BNLOG ("Can't be player of color %d\n", q.quest.m13489val); BNLOG ("Can't be player of color %d\n", q.quest->m13489val);
break; break;
} }
case CQuest::MISSION_KEYMASTER: case CQuest::MISSION_KEYMASTER:
@@ -2836,7 +2845,7 @@ TSubgoal CGoal::whatToDoToAchieve()
} }
} }
} }
if (o) if (o && isReachable(o))
return CGoal(GET_OBJ).setobjid(o->id); return CGoal(GET_OBJ).setobjid(o->id);
else else
return CGoal(EXPLORE); return CGoal(EXPLORE);
@@ -3522,15 +3531,25 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{ {
case Obj::BORDERGUARD: case Obj::BORDERGUARD:
case Obj::BORDER_GATE: case Obj::BORDER_GATE:
case Obj::SEER_HUT:
case Obj::QUEST_GUARD:
{ {
//return false; //fixme: avoid crash
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)) return false; // do not visit guards or gates when wandering
}
}
return true; //we don't have this quest yet
break;
}
case Obj::SEER_HUT:
case Obj::QUEST_GUARD:
{
BOOST_FOREACH (auto q, ai->myCb->getMyQuests())
{
if (q.obj == obj)
{
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

View File

@@ -356,6 +356,7 @@ public:
void completeGoal (const CGoal goal); //safely removes goal from reserved hero void completeGoal (const CGoal goal); //safely removes goal from reserved hero
void striveToQuest (const QuestInfo &q); void striveToQuest (const QuestInfo &q);
bool fulfillsGoal (CGoal &goal, CGoal &mainGoal); bool fulfillsGoal (CGoal &goal, CGoal &mainGoal);
bool fulfillsGoal (CGoal &goal, const CGoal &mainGoal); //TODO: something smarter
void recruitHero(const CGTownInstance * t); void recruitHero(const CGTownInstance * t);
std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h); std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h);

View File

@@ -139,7 +139,7 @@ void CQuestLog::init()
for (int i = 0; i < quests.size(); ++i) for (int i = 0; i < quests.size(); ++i)
{ {
MetaString text; MetaString text;
quests[i].quest.getRolloverText (text, false); quests[i].quest->getRolloverText (text, false);
if (quests[i].obj) if (quests[i].obj)
text.addReplacement (quests[i].obj->getHoverText()); //get name of the object text.addReplacement (quests[i].obj->getHoverText()); //get name of the object
CQuestLabel * label = new CQuestLabel (28, 199 + i * 24, FONT_SMALL, TOPLEFT, Colors::Cornsilk, text.toString()); CQuestLabel * label = new CQuestLabel (28, 199 + i * 24, FONT_SMALL, TOPLEFT, Colors::Cornsilk, text.toString());
@@ -191,7 +191,7 @@ void CQuestLog::selectQuest (int which)
MetaString text; MetaString text;
std::vector<Component> components; //TODO: display them std::vector<Component> components; //TODO: display them
currentQuest->quest.getVisitText (text, components , currentQuest->quest.isCustomFirst, true); currentQuest->quest->getVisitText (text, components , currentQuest->quest->isCustomFirst, true);
description->setTxt (text.toString()); //TODO: use special log entry text description->setTxt (text.toString()); //TODO: use special log entry text
redraw(); redraw();
} }

View File

@@ -469,13 +469,13 @@ public:
struct DLL_LINKAGE QuestInfo //universal interface for human and AI struct DLL_LINKAGE QuestInfo //universal interface for human and AI
{ {
CQuest quest; const CQuest * quest;
const CGObjectInstance * obj; //related object, most likely Seer Hut const CGObjectInstance * obj; //related object, most likely Seer Hut
int3 tile; int3 tile;
QuestInfo(){}; QuestInfo(){};
QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) : QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) :
quest (*Quest), obj (Obj), tile (Tile){}; quest (Quest), obj (Obj), tile (Tile){};
bool operator= (const QuestInfo &qi) bool operator= (const QuestInfo &qi)
{ {

View File

@@ -4402,42 +4402,42 @@ void CQuest::getCompletionText (MetaString &iwText, std::vector<Component> &comp
} }
void CGSeerHut::setObjToKill() void CGSeerHut::setObjToKill()
{ {
if (quest.missionType == CQuest::MISSION_KILL_CREATURE) if (quest->missionType == CQuest::MISSION_KILL_CREATURE)
{ {
quest.stackToKill = getCreatureToKill(false)->getStack(0); //FIXME: stacks tend to dissapear (desync?) on server :? quest->stackToKill = getCreatureToKill(false)->getStack(0); //FIXME: stacks tend to dissapear (desync?) on server :?
assert(quest.stackToKill.type); assert(quest->stackToKill.type);
quest.stackToKill.count = 0; //no count in info window quest->stackToKill.count = 0; //no count in info window
quest.stackDirection = checkDirection(); quest->stackDirection = checkDirection();
} }
else if (quest.missionType == CQuest::MISSION_KILL_HERO) else if (quest->missionType == CQuest::MISSION_KILL_HERO)
{ {
quest.heroName = getHeroToKill(false)->name; quest->heroName = getHeroToKill(false)->name;
quest.heroPortrait = getHeroToKill(false)->portrait; quest->heroPortrait = getHeroToKill(false)->portrait;
} }
} }
void CGSeerHut::initObj() void CGSeerHut::initObj()
{ {
seerName = VLC->generaltexth->seerNames[ran()%VLC->generaltexth->seerNames.size()]; seerName = VLC->generaltexth->seerNames[ran()%VLC->generaltexth->seerNames.size()];
quest.textOption = ran()%3; quest->textOption = ran()%3;
quest.progress = 0; quest->progress = 0;
if (quest.missionType) if (quest->missionType)
{ {
if (!quest.isCustomFirst) if (!quest->isCustomFirst)
quest.firstVisitText = VLC->generaltexth->quests[quest.missionType-1][0][quest.textOption]; quest->firstVisitText = VLC->generaltexth->quests[quest->missionType-1][0][quest->textOption];
if (!quest.isCustomNext) if (!quest->isCustomNext)
quest.nextVisitText = VLC->generaltexth->quests[quest.missionType-1][1][quest.textOption]; quest->nextVisitText = VLC->generaltexth->quests[quest->missionType-1][1][quest->textOption];
if (!quest.isCustomComplete) if (!quest->isCustomComplete)
quest.completedText = VLC->generaltexth->quests[quest.missionType-1][2][quest.textOption]; quest->completedText = VLC->generaltexth->quests[quest->missionType-1][2][quest->textOption];
} }
else else
quest.firstVisitText = VLC->generaltexth->seerEmpty[quest.textOption]; quest->firstVisitText = VLC->generaltexth->seerEmpty[quest->textOption];
} }
void CGSeerHut::getRolloverText (MetaString &text, bool onHover) const void CGSeerHut::getRolloverText (MetaString &text, bool onHover) const
{ {
quest.getRolloverText (text, onHover);//TODO: simplify? quest->getRolloverText (text, onHover);//TODO: simplify?
if (!onHover) if (!onHover)
text.addReplacement(seerName); text.addReplacement(seerName);
} }
@@ -4447,7 +4447,7 @@ const std::string & CGSeerHut::getHoverText() const
switch (ID) switch (ID)
{ {
case Obj::SEER_HUT: case Obj::SEER_HUT:
if (quest.progress) if (quest->progress)
{ {
hoverName = VLC->generaltexth->allTexts[347]; hoverName = VLC->generaltexth->allTexts[347];
boost::algorithm::replace_first(hoverName,"%s", seerName); boost::algorithm::replace_first(hoverName,"%s", seerName);
@@ -4461,7 +4461,7 @@ const std::string & CGSeerHut::getHoverText() const
default: default:
tlog5 << "unrecognized quest object\n"; tlog5 << "unrecognized quest object\n";
} }
if (quest.progress & quest.missionType) //rollover when the quest is active if (quest->progress & quest->missionType) //rollover when the quest is active
{ {
MetaString ms; MetaString ms;
getRolloverText (ms, true); getRolloverText (ms, true);
@@ -4489,17 +4489,17 @@ void CQuest::addReplacements(MetaString &out, const std::string &base) const
bool IQuestObject::checkQuest(const CGHeroInstance* h) const bool IQuestObject::checkQuest(const CGHeroInstance* h) const
{ {
return quest.checkQuest(h); return quest->checkQuest(h);
} }
void IQuestObject::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const void IQuestObject::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
{ {
quest.getVisitText (text,components, isCustom, FirstVisit, h); quest->getVisitText (text,components, isCustom, FirstVisit, h);
} }
void CGSeerHut::getCompletionText(MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const void CGSeerHut::getCompletionText(MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const
{ {
quest.getCompletionText (text, components, isCustom, h); quest->getCompletionText (text, components, isCustom, h);
switch (rewardType) switch (rewardType)
{ {
case 1: components.push_back(Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0, 0)); case 1: components.push_back(Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0, 0));
@@ -4530,16 +4530,16 @@ void CGSeerHut::setPropertyDer (ui8 what, ui32 val)
switch (what) switch (what)
{ {
case 10: case 10:
quest.progress = val; quest->progress = val;
break; break;
case 11: case 11:
quest.missionType = CQuest::MISSION_NONE; quest->missionType = CQuest::MISSION_NONE;
break; break;
} }
} }
void CGSeerHut::newTurn() const void CGSeerHut::newTurn() const
{ {
if (quest.lastDay >= 0 && quest.lastDay < cb->getDate(0)) //time is up if (quest->lastDay >= 0 && quest->lastDay < cb->getDate(0)) //time is up
{ {
cb->setObjProperty (id, 11, 0); cb->setObjProperty (id, 11, 0);
cb->setObjProperty (id, 10, 0); cb->setObjProperty (id, 10, 0);
@@ -4550,25 +4550,25 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
{ {
InfoWindow iw; InfoWindow iw;
iw.player = h->getOwner(); iw.player = h->getOwner();
if (quest.missionType) if (quest->missionType)
{ {
bool firstVisit = !quest.progress; bool firstVisit = !quest->progress;
bool failRequirements = !checkQuest(h); bool failRequirements = !checkQuest(h);
bool isCustom=false; bool isCustom=false;
if (firstVisit) if (firstVisit)
{ {
isCustom = quest.isCustomFirst; isCustom = quest->isCustomFirst;
cb->setObjProperty (id, 10, CQuest::IN_PROGRESS); cb->setObjProperty (id, 10, CQuest::IN_PROGRESS);
AddQuest aq; AddQuest aq;
aq.quest = QuestInfo (&quest, this, visitablePos()); aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner; aq.player = h->tempOwner;
cb->sendAndApply (&aq); //TODO: merge with setObjProperty? cb->sendAndApply (&aq); //TODO: merge with setObjProperty?
} }
else if (failRequirements) else if (failRequirements)
{ {
isCustom = quest.isCustomNext; isCustom = quest->isCustomNext;
} }
if (firstVisit || failRequirements) if (firstVisit || failRequirements)
@@ -4591,7 +4591,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
} }
else else
{ {
iw.text << VLC->generaltexth->seerEmpty[quest.textOption]; iw.text << VLC->generaltexth->seerEmpty[quest->textOption];
if (ID == Obj::SEER_HUT) if (ID == Obj::SEER_HUT)
iw.text.addReplacement(seerName); iw.text.addReplacement(seerName);
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
@@ -4632,21 +4632,21 @@ void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
{ {
if (accept) if (accept)
{ {
switch (quest.missionType) switch (quest->missionType)
{ {
case CQuest::MISSION_ART: case CQuest::MISSION_ART:
for (std::vector<ui16>::const_iterator it = quest.m5arts.begin(); it != quest.m5arts.end(); ++it) for (std::vector<ui16>::const_iterator it = quest->m5arts.begin(); it != quest->m5arts.end(); ++it)
{ {
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(*it, false))); cb->removeArtifact(ArtifactLocation(h, h->getArtPos(*it, false)));
} }
break; break;
case CQuest::MISSION_ARMY: case CQuest::MISSION_ARMY:
cb->takeCreatures(h->id, quest.m6creatures); cb->takeCreatures(h->id, quest->m6creatures);
break; break;
case CQuest::MISSION_RESOURCES: case CQuest::MISSION_RESOURCES:
for (int i = 0; i < 7; ++i) for (int i = 0; i < 7; ++i)
{ {
cb->giveResource(h->getOwner(), i, -quest.m7resources[i]); cb->giveResource(h->getOwner(), i, -quest->m7resources[i]);
} }
break; break;
default: default:
@@ -4715,7 +4715,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
{ {
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest.m13489val); const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val);
if(allowNull && !o) if(allowNull && !o)
return NULL; return NULL;
assert(o && o->ID == Obj::HERO); assert(o && o->ID == Obj::HERO);
@@ -4724,7 +4724,7 @@ const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
{ {
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest.m13489val); const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val);
if(allowNull && !o) if(allowNull && !o)
return NULL; return NULL;
assert(o && o->ID == Obj::MONSTER); assert(o && o->ID == Obj::MONSTER);
@@ -4734,19 +4734,19 @@ const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
void CGQuestGuard::initObj() void CGQuestGuard::initObj()
{ {
blockVisit = true; blockVisit = true;
quest.progress = 0; quest->progress = 0;
quest.textOption = ran()%3 + 3; //3-5 quest->textOption = ran()%3 + 3; //3-5
if (quest.missionType) if (quest->missionType)
{ {
if (!quest.isCustomFirst) if (!quest->isCustomFirst)
quest.firstVisitText = VLC->generaltexth->quests[quest.missionType-1][0][quest.textOption]; quest->firstVisitText = VLC->generaltexth->quests[quest->missionType-1][0][quest->textOption];
if (!quest.isCustomNext) if (!quest->isCustomNext)
quest.nextVisitText = VLC->generaltexth->quests[quest.missionType-1][1][quest.textOption]; quest->nextVisitText = VLC->generaltexth->quests[quest->missionType-1][1][quest->textOption];
if (!quest.isCustomComplete) if (!quest->isCustomComplete)
quest.completedText = VLC->generaltexth->quests[quest.missionType-1][2][quest.textOption]; quest->completedText = VLC->generaltexth->quests[quest->missionType-1][2][quest->textOption];
} }
else else
quest.firstVisitText = VLC->generaltexth->seerEmpty[quest.textOption]; quest->firstVisitText = VLC->generaltexth->seerEmpty[quest->textOption];
} }
void CGQuestGuard::completeQuest(const CGHeroInstance *h) const void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
{ {
@@ -6370,7 +6370,7 @@ void CGBorderGuard::onHeroVisit( const CGHeroInstance * h ) const
cb->showInfoDialog (&iw); cb->showInfoDialog (&iw);
AddQuest aq; AddQuest aq;
aq.quest = QuestInfo (&quest, this, visitablePos()); aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner; aq.player = h->tempOwner;
cb->sendAndApply (&aq); cb->sendAndApply (&aq);
//TODO: add this quest only once OR check for multiple instances later //TODO: add this quest only once OR check for multiple instances later
@@ -6393,7 +6393,7 @@ void CGBorderGate::onHeroVisit( const CGHeroInstance * h ) const //TODO: passabi
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
AddQuest aq; AddQuest aq;
aq.quest = QuestInfo (&quest, this, visitablePos()); aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner; aq.player = h->tempOwner;
cb->sendAndApply (&aq); cb->sendAndApply (&aq);
} }

View File

@@ -771,8 +771,9 @@ public:
class DLL_LINKAGE IQuestObject class DLL_LINKAGE IQuestObject
{ {
public: public:
CQuest quest; CQuest * quest;
IQuestObject(){quest = new CQuest;};
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 bool checkQuest (const CGHeroInstance * h) const; virtual bool checkQuest (const CGHeroInstance * h) const;
@@ -790,6 +791,7 @@ public:
si32 rVal; //reward value si32 rVal; //reward value
std::string seerName; std::string seerName;
CGSeerHut() : IQuestObject(){};
void initObj(); void initObj();
const std::string & getHoverText() const; const std::string & getHoverText() const;
void setPropertyDer (ui8 what, ui32 val); void setPropertyDer (ui8 what, ui32 val);
@@ -815,6 +817,7 @@ public:
class DLL_LINKAGE CGQuestGuard : public CGSeerHut class DLL_LINKAGE CGQuestGuard : public CGSeerHut
{ {
public: public:
CGQuestGuard() : CGSeerHut(){};
void initObj(); void initObj();
void completeQuest (const CGHeroInstance * h) const; void completeQuest (const CGHeroInstance * h) const;
@@ -1093,6 +1096,7 @@ public:
class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject
{ {
public: public:
CGBorderGuard() : IQuestObject(){};
void initObj(); void initObj();
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;
@@ -1112,6 +1116,7 @@ public:
class DLL_LINKAGE CGBorderGate : public CGBorderGuard class DLL_LINKAGE CGBorderGate : public CGBorderGuard
{ {
public: public:
CGBorderGate() : CGBorderGuard(){};
void onHeroVisit(const CGHeroInstance * h) const; void onHeroVisit(const CGHeroInstance * h) const;
ui8 getPassableness() const; ui8 getPassableness() const;

View File

@@ -595,18 +595,18 @@ int Mapa::loadSeerHut( const ui8 * bufor, int i, CGObjectInstance *& nobj )
int artID = bufor[i]; ++i; int artID = bufor[i]; ++i;
if (artID != 255) //not none quest if (artID != 255) //not none quest
{ {
hut->quest.m5arts.push_back (artID); hut->quest->m5arts.push_back (artID);
hut->quest.missionType = CQuest::MISSION_ART; hut->quest->missionType = CQuest::MISSION_ART;
} }
else else
{ {
hut->quest.missionType = CQuest::MISSION_NONE; //no mission hut->quest->missionType = CQuest::MISSION_NONE; //no mission
} }
hut->quest.lastDay = -1; //no timeout hut->quest->lastDay = -1; //no timeout
hut->quest.isCustomFirst = hut->quest.isCustomNext = hut->quest.isCustomComplete = false; hut->quest->isCustomFirst = hut->quest->isCustomNext = hut->quest->isCustomComplete = false;
} }
if (hut->quest.missionType) if (hut->quest->missionType)
{ {
ui8 rewardType = bufor[i]; ++i; ui8 rewardType = bufor[i]; ++i;
hut->rewardType = rewardType; hut->rewardType = rewardType;
@@ -1489,7 +1489,7 @@ void Mapa::readObjects( const ui8 * bufor, int &i)
case 83: //seer's hut case 83: //seer's hut
{ {
i = loadSeerHut(bufor, i, nobj); i = loadSeerHut(bufor, i, nobj);
addQuest (dynamic_cast<IQuestObject *>(nobj)); addQuest (nobj);
break; break;
} }
case 113: //witch hut case 113: //witch hut
@@ -1748,9 +1748,9 @@ void Mapa::readObjects( const ui8 * bufor, int &i)
case 215: case 215:
{ {
CGQuestGuard *guard = new CGQuestGuard(); CGQuestGuard *guard = new CGQuestGuard();
nobj = guard; addQuest (guard);
loadQuest(guard, bufor, i); loadQuest(guard, bufor, i);
addQuest (dynamic_cast <IQuestObject *>(guard)); nobj = guard;
break; break;
} }
case 28: //faerie ring case 28: //faerie ring
@@ -1831,13 +1831,13 @@ void Mapa::readObjects( const ui8 * bufor, int &i)
case 9: //Border Guard case 9: //Border Guard
{ {
nobj = new CGBorderGuard(); nobj = new CGBorderGuard();
addQuest (dynamic_cast<IQuestObject *>(nobj)); addQuest (nobj);
break; break;
} }
case 212: //Border Gate case 212: //Border Gate
{ {
nobj = new CGBorderGate(); nobj = new CGBorderGate();
addQuest (dynamic_cast<IQuestObject *>(nobj)); addQuest (nobj);
break; break;
} }
case 27: case 37: //Eye and Hut of Magi case 27: case 37: //Eye and Hut of Magi
@@ -1975,18 +1975,18 @@ bool Mapa::isInTheMap(const int3 &pos) const
void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i) void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
{ {
guard->quest.missionType = bufor[i]; ++i; guard->quest->missionType = bufor[i]; ++i;
//int len1, len2, len3; //int len1, len2, len3;
switch(guard->quest.missionType) switch(guard->quest->missionType)
{ {
case 0: case 0:
return; return;
case 2: case 2:
{ {
guard->quest.m2stats.resize(4); guard->quest->m2stats.resize(4);
for(int x=0; x<4; x++) for(int x=0; x<4; x++)
{ {
guard->quest.m2stats[x] = bufor[i++]; guard->quest->m2stats[x] = bufor[i++];
} }
} }
break; break;
@@ -1994,7 +1994,7 @@ void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
case 3: case 3:
case 4: case 4:
{ {
guard->quest.m13489val = read_le_u32(bufor + i); i+=4; guard->quest->m13489val = read_le_u32(bufor + i); i+=4;
break; break;
} }
case 5: case 5:
@@ -2003,7 +2003,7 @@ void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
for(int yy=0; yy<artNumber; ++yy) for(int yy=0; yy<artNumber; ++yy)
{ {
int artid = read_le_u16(bufor + i); i+=2; int artid = read_le_u16(bufor + i); i+=2;
guard->quest.m5arts.push_back(artid); guard->quest->m5arts.push_back(artid);
allowedArtifact[artid] = false; //these are unavailable for random generation allowedArtifact[artid] = false; //these are unavailable for random generation
} }
break; break;
@@ -2011,20 +2011,20 @@ void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
case 6: case 6:
{ {
int typeNumber = bufor[i]; ++i; int typeNumber = bufor[i]; ++i;
guard->quest.m6creatures.resize(typeNumber); guard->quest->m6creatures.resize(typeNumber);
for(int hh=0; hh<typeNumber; ++hh) for(int hh=0; hh<typeNumber; ++hh)
{ {
guard->quest.m6creatures[hh].type = VLC->creh->creatures[read_le_u16(bufor + i)]; i+=2; guard->quest->m6creatures[hh].type = VLC->creh->creatures[read_le_u16(bufor + i)]; i+=2;
guard->quest.m6creatures[hh].count = read_le_u16(bufor + i); i+=2; guard->quest->m6creatures[hh].count = read_le_u16(bufor + i); i+=2;
} }
break; break;
} }
case 7: case 7:
{ {
guard->quest.m7resources.resize(7); guard->quest->m7resources.resize(7);
for(int x=0; x<7; x++) for(int x=0; x<7; x++)
{ {
guard->quest.m7resources[x] = read_le_u32(bufor + i); guard->quest->m7resources[x] = read_le_u32(bufor + i);
i+=4; i+=4;
} }
break; break;
@@ -2032,7 +2032,7 @@ void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
case 8: case 8:
case 9: case 9:
{ {
guard->quest.m13489val = bufor[i]; ++i; guard->quest->m13489val = bufor[i]; ++i;
break; break;
} }
} }
@@ -2041,18 +2041,18 @@ void Mapa::loadQuest(IQuestObject * guard, const ui8 * bufor, int & i)
int limit = read_le_u32(bufor + i); i+=4; int limit = read_le_u32(bufor + i); i+=4;
if(limit == ((int)0xffffffff)) if(limit == ((int)0xffffffff))
{ {
guard->quest.lastDay = -1; guard->quest->lastDay = -1;
} }
else else
{ {
guard->quest.lastDay = limit; guard->quest->lastDay = limit;
} }
guard->quest.firstVisitText = readString(bufor,i); guard->quest->firstVisitText = readString(bufor,i);
guard->quest.nextVisitText = readString(bufor,i); guard->quest->nextVisitText = readString(bufor,i);
guard->quest.completedText = readString(bufor,i); guard->quest->completedText = readString(bufor,i);
guard->quest.isCustomFirst = guard->quest.firstVisitText.size() > 0; guard->quest->isCustomFirst = guard->quest->firstVisitText.size() > 0;
guard->quest.isCustomNext = guard->quest.nextVisitText.size() > 0; guard->quest->isCustomNext = guard->quest->nextVisitText.size() > 0;
guard->quest.isCustomComplete = guard->quest.completedText.size() > 0; guard->quest->isCustomComplete = guard->quest->completedText.size() > 0;
} }
TerrainTile & Mapa::getTile( const int3 & tile ) TerrainTile & Mapa::getTile( const int3 & tile )
@@ -2098,10 +2098,11 @@ void Mapa::addNewArtifactInstance( CArtifactInstance *art )
artInstances.push_back(art); artInstances.push_back(art);
} }
void Mapa::addQuest (IQuestObject *obj) void Mapa::addQuest (CGObjectInstance *obj)
{ {
obj->quest.qid = quests.size(); auto q = dynamic_cast<IQuestObject *>(obj);
quests.push_back(&obj->quest); q->quest->qid = quests.size();
quests.push_back (q->quest);
} }
bool Mapa::loadArtifactToSlot(CGHeroInstance *h, int slot, const ui8 * bufor, int &i) bool Mapa::loadArtifactToSlot(CGHeroInstance *h, int slot, const ui8 * bufor, int &i)

View File

@@ -335,7 +335,7 @@ struct DLL_LINKAGE Mapa : public CMapHeader
CArtifactInstance *createArt(int aid, int spellID = -1); CArtifactInstance *createArt(int aid, int spellID = -1);
void addNewArtifactInstance(CArtifactInstance *art); void addNewArtifactInstance(CArtifactInstance *art);
void addQuest (IQuestObject *quest); void addQuest (CGObjectInstance *obj);
void eraseArtifactInstance(CArtifactInstance *art); void eraseArtifactInstance(CArtifactInstance *art);
@@ -358,7 +358,7 @@ struct DLL_LINKAGE Mapa : public CMapHeader
{ {
h & static_cast<CMapHeader&>(*this); h & static_cast<CMapHeader&>(*this);
h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos;
h & artInstances; //hopefully serialization is now automagical? h & artInstances & quests; //hopefully serialization is now automagical?
h & questIdentifierToId; h & questIdentifierToId;
//TODO: viccondetails //TODO: viccondetails