mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Remove quests from CMap, now solely owned by quest objects
This commit is contained in:
@@ -657,7 +657,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
|
||||
{
|
||||
for(auto q : ai->cb->getMyQuests())
|
||||
{
|
||||
if(q.obj == obj)
|
||||
if(q.obj == obj->id)
|
||||
{
|
||||
return false; // do not visit guards or gates when wandering
|
||||
}
|
||||
@@ -670,9 +670,9 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
|
||||
{
|
||||
for(auto q : ai->cb->getMyQuests())
|
||||
{
|
||||
if(q.obj == obj)
|
||||
if(q.obj == obj->id)
|
||||
{
|
||||
if(q.quest->checkQuest(h))
|
||||
if(q.getQuest(cb)->checkQuest(h))
|
||||
return true; //we completed the quest
|
||||
else
|
||||
return false; //we can't complete this quest
|
||||
|
@@ -22,7 +22,8 @@ using namespace Goals;
|
||||
|
||||
bool isKeyMaster(const QuestInfo & q)
|
||||
{
|
||||
return q.obj && (q.obj->ID == Obj::BORDER_GATE || q.obj->ID == Obj::BORDERGUARD);
|
||||
auto object = q.getObject(cb);
|
||||
return object && (object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD);
|
||||
}
|
||||
|
||||
std::string CompleteQuest::toString() const
|
||||
@@ -38,27 +39,28 @@ TGoalVec CompleteQuest::decompose(const Nullkiller * ai) const
|
||||
}
|
||||
|
||||
logAi->debug("Trying to realize quest: %s", questToString());
|
||||
|
||||
if(!q.quest->mission.artifacts.empty())
|
||||
auto quest = q.getQuest(cb);
|
||||
|
||||
if(!quest->mission.artifacts.empty())
|
||||
return missionArt(ai);
|
||||
|
||||
if(!q.quest->mission.heroes.empty())
|
||||
if(!quest->mission.heroes.empty())
|
||||
return missionHero(ai);
|
||||
|
||||
if(!q.quest->mission.creatures.empty())
|
||||
if(!quest->mission.creatures.empty())
|
||||
return missionArmy(ai);
|
||||
|
||||
if(q.quest->mission.resources.nonZero())
|
||||
if(quest->mission.resources.nonZero())
|
||||
return missionResources(ai);
|
||||
|
||||
if(q.quest->killTarget != ObjectInstanceID::NONE)
|
||||
if(quest->killTarget != ObjectInstanceID::NONE)
|
||||
return missionDestroyObj(ai);
|
||||
|
||||
for(auto & s : q.quest->mission.primary)
|
||||
for(auto & s : quest->mission.primary)
|
||||
if(s)
|
||||
return missionIncreasePrimaryStat(ai);
|
||||
|
||||
if(q.quest->mission.heroLevel > 0)
|
||||
if(quest->mission.heroLevel > 0)
|
||||
return missionLevel(ai);
|
||||
|
||||
return TGoalVec();
|
||||
@@ -68,52 +70,52 @@ bool CompleteQuest::operator==(const CompleteQuest & other) const
|
||||
{
|
||||
if(isKeyMaster(q))
|
||||
{
|
||||
return isKeyMaster(other.q) && q.obj->subID == other.q.obj->subID;
|
||||
return isKeyMaster(other.q) && q.getObject(cb)->subID == other.q.getObject(cb)->subID;
|
||||
}
|
||||
else if(isKeyMaster(other.q))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return q.quest->qid == other.q.quest->qid;
|
||||
return q.getQuest(cb) == other.q.getQuest(cb);
|
||||
}
|
||||
|
||||
uint64_t CompleteQuest::getHash() const
|
||||
{
|
||||
if(isKeyMaster(q))
|
||||
{
|
||||
return q.obj->subID;
|
||||
return q.getObject(cb)->subID;
|
||||
}
|
||||
|
||||
return q.quest->qid;
|
||||
return q.getObject(cb)->id;
|
||||
}
|
||||
|
||||
std::string CompleteQuest::questToString() const
|
||||
{
|
||||
if(isKeyMaster(q))
|
||||
{
|
||||
return "find " + LIBRARY->generaltexth->tentColors[q.obj->subID] + " keymaster tent";
|
||||
return "find " + LIBRARY->generaltexth->tentColors[q.getObject(cb)->subID] + " keymaster tent";
|
||||
}
|
||||
|
||||
if(q.quest->questName == CQuest::missionName(EQuestMission::NONE))
|
||||
if(q.getQuest(cb)->questName == CQuest::missionName(EQuestMission::NONE))
|
||||
return "inactive quest";
|
||||
|
||||
MetaString ms;
|
||||
q.quest->getRolloverText(q.obj->cb, ms, false);
|
||||
q.getQuest(cb)->getRolloverText(cb, ms, false);
|
||||
|
||||
return ms.toString();
|
||||
}
|
||||
|
||||
TGoalVec CompleteQuest::tryCompleteQuest(const Nullkiller * ai) const
|
||||
{
|
||||
auto paths = ai->pathfinder->getPathInfo(q.obj->visitablePos());
|
||||
auto paths = ai->pathfinder->getPathInfo(q.getObject(cb)->visitablePos());
|
||||
|
||||
vstd::erase_if(paths, [&](const AIPath & path) -> bool
|
||||
{
|
||||
return !q.quest->checkQuest(path.targetHero);
|
||||
return !q.getQuest(cb)->checkQuest(path.targetHero);
|
||||
});
|
||||
|
||||
return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.obj);
|
||||
return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.getObject(cb));
|
||||
}
|
||||
|
||||
TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const
|
||||
@@ -125,7 +127,7 @@ TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const
|
||||
|
||||
CaptureObjectsBehavior findArts;
|
||||
|
||||
for(auto art : q.quest->mission.artifacts)
|
||||
for(auto art : q.getQuest(cb)->mission.artifacts)
|
||||
{
|
||||
solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art)));
|
||||
}
|
||||
@@ -148,14 +150,14 @@ TGoalVec CompleteQuest::missionHero(const Nullkiller * ai) const
|
||||
|
||||
TGoalVec CompleteQuest::missionArmy(const Nullkiller * ai) const
|
||||
{
|
||||
auto paths = ai->pathfinder->getPathInfo(q.obj->visitablePos());
|
||||
auto paths = ai->pathfinder->getPathInfo(q.getObject(cb)->visitablePos());
|
||||
|
||||
vstd::erase_if(paths, [&](const AIPath & path) -> bool
|
||||
{
|
||||
return !CQuest::checkMissionArmy(q.quest, path.heroArmy);
|
||||
return !CQuest::checkMissionArmy(q.getQuest(cb), path.heroArmy);
|
||||
});
|
||||
|
||||
return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.obj);
|
||||
return CaptureObjectsBehavior::getVisitGoals(paths, ai, q.getObject(cb));
|
||||
}
|
||||
|
||||
TGoalVec CompleteQuest::missionIncreasePrimaryStat(const Nullkiller * ai) const
|
||||
@@ -170,13 +172,13 @@ TGoalVec CompleteQuest::missionLevel(const Nullkiller * ai) const
|
||||
|
||||
TGoalVec CompleteQuest::missionKeymaster(const Nullkiller * ai) const
|
||||
{
|
||||
if(isObjectPassable(ai, q.obj))
|
||||
if(isObjectPassable(ai, q.getObject(cb)))
|
||||
{
|
||||
return CaptureObjectsBehavior(q.obj).decompose(ai);
|
||||
return CaptureObjectsBehavior(q.getObject(cb)).decompose(ai);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.obj->subID).decompose(ai);
|
||||
return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.getObject(cb)->subID).decompose(ai);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,16 +190,16 @@ TGoalVec CompleteQuest::missionResources(const Nullkiller * ai) const
|
||||
|
||||
if(heroes.size())
|
||||
{
|
||||
if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
||||
if(q.getQuest(cb)->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
||||
{
|
||||
return solutions;// ai->ah->howToVisitObj(q.obj);
|
||||
return solutions;// ai->ah->howToVisitObj(q.getObject(cb));
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < q.quest->m7resources.size(); ++i)
|
||||
for(int i = 0; i < q.getQuest(cb)->m7resources.size(); ++i)
|
||||
{
|
||||
if(q.quest->m7resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
|
||||
if(q.getQuest(cb)->m7resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.getQuest(cb)->m7resources[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,10 +213,10 @@ TGoalVec CompleteQuest::missionResources(const Nullkiller * ai) const
|
||||
|
||||
TGoalVec CompleteQuest::missionDestroyObj(const Nullkiller * ai) const
|
||||
{
|
||||
auto obj = ai->cb->getObj(q.quest->killTarget);
|
||||
auto obj = ai->cb->getObj(q.getQuest(cb)->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return CaptureObjectsBehavior(q.obj).decompose(ai);
|
||||
return CaptureObjectsBehavior(q.getObject(cb)).decompose(ai);
|
||||
|
||||
auto relations = ai->cb->getPlayerRelations(ai->playerID, obj->tempOwner);
|
||||
|
||||
|
@@ -31,16 +31,18 @@ namespace AIPathfinding
|
||||
|
||||
bool QuestAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero) const
|
||||
{
|
||||
if(questInfo.obj->ID == Obj::BORDER_GATE || questInfo.obj->ID == Obj::BORDERGUARD)
|
||||
auto object = questInfo.getObject(cb);
|
||||
auto quest = questInfo.getQuest(cb);
|
||||
if(object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD)
|
||||
{
|
||||
return dynamic_cast<const IQuestObject *>(questInfo.obj)->checkQuest(hero);
|
||||
return dynamic_cast<const IQuestObject *>(object)->checkQuest(hero);
|
||||
}
|
||||
|
||||
auto notActivated = !questInfo.obj->wasVisited(ai->playerID)
|
||||
&& !questInfo.quest->activeForPlayers.count(hero->getOwner());
|
||||
auto notActivated = !object->wasVisited(ai->playerID)
|
||||
&& !quest->activeForPlayers.count(hero->getOwner());
|
||||
|
||||
return notActivated
|
||||
|| questInfo.quest->checkQuest(hero);
|
||||
|| quest->checkQuest(hero);
|
||||
}
|
||||
|
||||
Goals::TSubgoal QuestAction::decompose(const Nullkiller * ai, const CGHeroInstance * hero) const
|
||||
@@ -50,7 +52,7 @@ namespace AIPathfinding
|
||||
|
||||
void QuestAction::execute(AIGateway * ai, const CGHeroInstance * hero) const
|
||||
{
|
||||
ai->moveHeroToTile(questInfo.obj->visitablePos(), hero);
|
||||
ai->moveHeroToTile(questInfo.getObject(cb)->visitablePos(), hero);
|
||||
}
|
||||
|
||||
std::string QuestAction::toString() const
|
||||
|
@@ -83,11 +83,11 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
|
||||
|| node.obj->ID == Obj::BORDER_GATE)
|
||||
{
|
||||
auto questObj = dynamic_cast<const IQuestObject *>(node.obj);
|
||||
auto questInfo = QuestInfo(questObj->getQuest(), node.obj, pos.coord);
|
||||
auto questInfo = QuestInfo(node.obj->id);
|
||||
|
||||
if(node.obj->ID == Obj::QUEST_GUARD
|
||||
&& questObj->getQuest()->mission == Rewardable::Limiter{}
|
||||
&& questObj->getQuest()->killTarget == ObjectInstanceID::NONE)
|
||||
&& questObj->getQuest().mission == Rewardable::Limiter{}
|
||||
&& questObj->getQuest().killTarget == ObjectInstanceID::NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@@ -166,12 +166,12 @@ namespace AIPathfinding
|
||||
{
|
||||
const AIPathNode * destinationNode = nodeStorage->getAINode(destination.node);
|
||||
auto questObj = dynamic_cast<const IQuestObject *>(destination.nodeObject);
|
||||
auto questInfo = QuestInfo(questObj->getQuest(), destination.nodeObject, destination.coord);
|
||||
auto questInfo = QuestInfo(destination.nodeObject->id);
|
||||
QuestAction questAction(questInfo);
|
||||
|
||||
if(destination.nodeObject->ID == Obj::QUEST_GUARD
|
||||
&& questObj->getQuest()->mission == Rewardable::Limiter{}
|
||||
&& questObj->getQuest()->killTarget == ObjectInstanceID::NONE)
|
||||
&& questObj->getQuest().mission == Rewardable::Limiter{}
|
||||
&& questObj->getQuest().killTarget == ObjectInstanceID::NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "FuzzyHelper.h"
|
||||
|
||||
#include "Goals/Goals.h"
|
||||
#include "Goals/CompleteQuest.h"
|
||||
#include "VCAI.h"
|
||||
|
||||
#include "../../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
|
@@ -8,7 +8,15 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "Goals.h"
|
||||
#include "CompleteQuest.h"
|
||||
|
||||
#include "CollectRes.h"
|
||||
#include "FindObj.h"
|
||||
#include "GatherArmy.h"
|
||||
#include "GatherTroops.h"
|
||||
#include "GetArtOfType.h"
|
||||
#include "RecruitHero.h"
|
||||
|
||||
#include "../VCAI.h"
|
||||
#include "../FuzzyHelper.h"
|
||||
#include "../AIhelper.h"
|
||||
@@ -18,45 +26,47 @@ using namespace Goals;
|
||||
|
||||
bool CompleteQuest::operator==(const CompleteQuest & other) const
|
||||
{
|
||||
return q.quest->qid == other.q.quest->qid;
|
||||
return q.getQuest(cb) == other.q.getQuest(cb);
|
||||
}
|
||||
|
||||
bool isKeyMaster(const QuestInfo & q)
|
||||
{
|
||||
return q.obj && (q.obj->ID == Obj::BORDER_GATE || q.obj->ID == Obj::BORDERGUARD);
|
||||
auto object = q.getObject(cb);
|
||||
return object && (object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD);
|
||||
}
|
||||
|
||||
TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
||||
{
|
||||
TGoalVec solutions;
|
||||
auto quest = q.getQuest(cb);
|
||||
|
||||
if(!q.quest->isCompleted)
|
||||
if(!quest->isCompleted)
|
||||
{
|
||||
logAi->debug("Trying to realize quest: %s", questToString());
|
||||
|
||||
if(isKeyMaster(q))
|
||||
return missionKeymaster();
|
||||
|
||||
if(!q.quest->mission.artifacts.empty())
|
||||
if(!quest->mission.artifacts.empty())
|
||||
return missionArt();
|
||||
|
||||
if(!q.quest->mission.heroes.empty())
|
||||
if(!quest->mission.heroes.empty())
|
||||
return missionHero();
|
||||
|
||||
if(!q.quest->mission.creatures.empty())
|
||||
if(!quest->mission.creatures.empty())
|
||||
return missionArmy();
|
||||
|
||||
if(q.quest->mission.resources.nonZero())
|
||||
if(quest->mission.resources.nonZero())
|
||||
return missionResources();
|
||||
|
||||
if(q.quest->killTarget != ObjectInstanceID::NONE)
|
||||
if(quest->killTarget != ObjectInstanceID::NONE)
|
||||
return missionDestroyObj();
|
||||
|
||||
for(auto & s : q.quest->mission.primary)
|
||||
for(auto & s : quest->mission.primary)
|
||||
if(s)
|
||||
return missionIncreasePrimaryStat();
|
||||
|
||||
if(q.quest->mission.heroLevel > 0)
|
||||
if(quest->mission.heroLevel > 0)
|
||||
return missionLevel();
|
||||
}
|
||||
|
||||
@@ -65,7 +75,7 @@ TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
||||
|
||||
TSubgoal CompleteQuest::whatToDoToAchieve()
|
||||
{
|
||||
if(q.quest->mission == Rewardable::Limiter{})
|
||||
if(q.getQuest(cb)->mission == Rewardable::Limiter{})
|
||||
{
|
||||
throw cannotFulfillGoalException("Can not complete inactive quest");
|
||||
}
|
||||
@@ -99,11 +109,13 @@ std::string CompleteQuest::completeMessage() const
|
||||
|
||||
std::string CompleteQuest::questToString() const
|
||||
{
|
||||
if(q.quest->questName == CQuest::missionName(EQuestMission::NONE))
|
||||
auto quest = q.getQuest(cb);
|
||||
|
||||
if(quest->questName == CQuest::missionName(EQuestMission::NONE))
|
||||
return "inactive quest";
|
||||
|
||||
MetaString ms;
|
||||
q.quest->getRolloverText(q.obj->cb, ms, false);
|
||||
quest->getRolloverText(cb, ms, false);
|
||||
|
||||
return ms.toString();
|
||||
}
|
||||
@@ -116,9 +128,9 @@ TGoalVec CompleteQuest::tryCompleteQuest() const
|
||||
|
||||
for(auto hero : heroes)
|
||||
{
|
||||
if(q.quest->checkQuest(hero))
|
||||
if(q.getQuest(cb)->checkQuest(hero))
|
||||
{
|
||||
vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.obj->id)));
|
||||
vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.getObject(cb)->id)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +144,7 @@ TGoalVec CompleteQuest::missionArt() const
|
||||
if(!solutions.empty())
|
||||
return solutions;
|
||||
|
||||
for(auto art : q.quest->mission.artifacts)
|
||||
for(auto art : q.getQuest(cb)->mission.artifacts)
|
||||
{
|
||||
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
||||
}
|
||||
@@ -160,7 +172,7 @@ TGoalVec CompleteQuest::missionArmy() const
|
||||
if(!solutions.empty())
|
||||
return solutions;
|
||||
|
||||
for(auto creature : q.quest->mission.creatures)
|
||||
for(auto creature : q.getQuest(cb)->mission.creatures)
|
||||
{
|
||||
solutions.push_back(sptr(GatherTroops(creature.getId(), creature.count)));
|
||||
}
|
||||
@@ -174,7 +186,7 @@ TGoalVec CompleteQuest::missionIncreasePrimaryStat() const
|
||||
|
||||
if(solutions.empty())
|
||||
{
|
||||
for(int i = 0; i < q.quest->mission.primary.size(); ++i)
|
||||
for(int i = 0; i < q.getQuest(cb)->mission.primary.size(); ++i)
|
||||
{
|
||||
// TODO: library, school and other boost objects
|
||||
logAi->debug("Don't know how to increase primary stat %d", i);
|
||||
@@ -190,7 +202,7 @@ TGoalVec CompleteQuest::missionLevel() const
|
||||
|
||||
if(solutions.empty())
|
||||
{
|
||||
logAi->debug("Don't know how to reach hero level %d", q.quest->mission.heroLevel);
|
||||
logAi->debug("Don't know how to reach hero level %d", q.getQuest(cb)->mission.heroLevel);
|
||||
}
|
||||
|
||||
return solutions;
|
||||
@@ -202,7 +214,7 @@ TGoalVec CompleteQuest::missionKeymaster() const
|
||||
|
||||
if(solutions.empty())
|
||||
{
|
||||
solutions.push_back(sptr(Goals::FindObj(Obj::KEYMASTER, q.obj->subID)));
|
||||
solutions.push_back(sptr(Goals::FindObj(Obj::KEYMASTER, q.getObject(cb)->subID)));
|
||||
}
|
||||
|
||||
return solutions;
|
||||
@@ -216,16 +228,16 @@ TGoalVec CompleteQuest::missionResources() const
|
||||
|
||||
if(heroes.size())
|
||||
{
|
||||
if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
||||
if(q.getQuest(cb)->checkQuest(heroes.front())) //it doesn't matter which hero it is
|
||||
{
|
||||
return ai->ah->howToVisitObj(q.obj);
|
||||
return ai->ah->howToVisitObj(q.getObject(cb));
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < q.quest->mission.resources.size(); ++i)
|
||||
for(int i = 0; i < q.getQuest(cb)->mission.resources.size(); ++i)
|
||||
{
|
||||
if(q.quest->mission.resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->mission.resources[i])));
|
||||
if(q.getQuest(cb)->mission.resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.getQuest(cb)->mission.resources[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,10 +253,10 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
||||
{
|
||||
TGoalVec solutions;
|
||||
|
||||
auto obj = cb->getObj(q.quest->killTarget);
|
||||
auto obj = cb->getObj(q.getQuest(cb)->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return ai->ah->howToVisitObj(q.obj);
|
||||
return ai->ah->howToVisitObj(q.getObject(cb));
|
||||
|
||||
if(obj->ID == Obj::HERO)
|
||||
{
|
||||
|
@@ -30,5 +30,4 @@
|
||||
#include "ClearWayTo.h"
|
||||
#include "DigAtTile.h"
|
||||
#include "FindObj.h"
|
||||
#include "CompleteQuest.h"
|
||||
#include "AdventureSpellCast.h"
|
||||
#include "AdventureSpellCast.h"
|
||||
|
@@ -12,7 +12,9 @@
|
||||
#include "AIPathfinder.h"
|
||||
#include "AIPathfinderConfig.h"
|
||||
#include "../Goals/Goals.h"
|
||||
#include "../Goals/CompleteQuest.h"
|
||||
#include "../../../lib/CGameInfoCallback.h"
|
||||
#include "../../../lib/gameState/QuestInfo.h"
|
||||
#include "../../../lib/mapping/CMapDefines.h"
|
||||
#include "../../../lib/mapObjects/CQuest.h"
|
||||
|
||||
@@ -224,7 +226,7 @@ Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet
|
||||
|
||||
if(questObj)
|
||||
{
|
||||
auto questInfo = QuestInfo(questObj->getQuest(), topObj, topObj->visitablePos());
|
||||
auto questInfo = QuestInfo(topObj->id);
|
||||
|
||||
return sptr(Goals::CompleteQuest(questInfo));
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "ResourceManager.h"
|
||||
#include "BuildingManager.h"
|
||||
#include "Goals/Goals.h"
|
||||
#include "Goals/CompleteQuest.h"
|
||||
|
||||
#include "../../lib/ArtifactUtils.h"
|
||||
#include "../../lib/AsyncRunner.h"
|
||||
@@ -2809,7 +2810,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
||||
{
|
||||
for(auto q : ai->myCb->getMyQuests())
|
||||
{
|
||||
if(q.obj == obj)
|
||||
if(q.getObject(cb) == obj)
|
||||
{
|
||||
return false; // do not visit guards or gates when wandering
|
||||
}
|
||||
@@ -2823,9 +2824,9 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
||||
{
|
||||
for(auto q : ai->myCb->getMyQuests())
|
||||
{
|
||||
if(q.obj == obj)
|
||||
if(q.getObject(cb) == obj)
|
||||
{
|
||||
if(q.quest->checkQuest(h.h))
|
||||
if(q.getQuest(cb)->checkQuest(h.h))
|
||||
return true; //we completed the quest
|
||||
else
|
||||
return false; //we can't complete this quest
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include "../CPlayerInterface.h"
|
||||
|
||||
#include "../GameEngine.h"
|
||||
#include "../GameInstance.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../gui/Shortcut.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/CComponent.h"
|
||||
@@ -74,11 +76,7 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
|
||||
OBJECT_CONSTRUCTION;
|
||||
icons.clear();
|
||||
|
||||
int3 tile;
|
||||
if (q->obj)
|
||||
tile = q->obj->visitablePos();
|
||||
else
|
||||
tile = q->tile;
|
||||
int3 tile = q->getPosition(GAME->interface()->cb.get());
|
||||
|
||||
Point offset = tileToPixels(tile);
|
||||
|
||||
@@ -102,7 +100,7 @@ void CQuestMinimap::update()
|
||||
void CQuestMinimap::iconClicked()
|
||||
{
|
||||
if(currentQuest->obj)
|
||||
adventureInt->centerOnTile(currentQuest->obj->visitablePos());
|
||||
adventureInt->centerOnTile(currentQuest->getObject(GAME->interface()->cb.get())->visitablePos());
|
||||
//moveAdvMapSelection();
|
||||
}
|
||||
|
||||
@@ -145,11 +143,14 @@ void CQuestLog::recreateLabelList()
|
||||
int currentLabel = 0;
|
||||
for (int i = 0; i < quests.size(); ++i)
|
||||
{
|
||||
auto questPtr = quests[i].getQuest(GAME->interface()->cb.get());
|
||||
auto questObject = quests[i].getObject(GAME->interface()->cb.get());
|
||||
|
||||
// Quests without mision don't have text for them and can't be displayed
|
||||
if (quests[i].quest->mission == Rewardable::Limiter{})
|
||||
if (quests[i].getQuest(GAME->interface()->cb.get())->mission == Rewardable::Limiter{})
|
||||
continue;
|
||||
|
||||
if (quests[i].quest->isCompleted)
|
||||
if (questPtr->isCompleted)
|
||||
{
|
||||
completeMissing = false;
|
||||
if (hideComplete)
|
||||
@@ -157,10 +158,10 @@ void CQuestLog::recreateLabelList()
|
||||
}
|
||||
|
||||
MetaString text;
|
||||
quests[i].quest->getRolloverText (quests[i].obj->cb, text, false);
|
||||
questPtr->getRolloverText(GAME->interface()->cb.get(), text, false);
|
||||
if (quests[i].obj)
|
||||
{
|
||||
if (auto seersHut = dynamic_cast<const CGSeerHut *>(quests[i].obj))
|
||||
if (auto seersHut = dynamic_cast<const CGSeerHut *>(questObject))
|
||||
{
|
||||
MetaString toSeer;
|
||||
toSeer.appendRawString(LIBRARY->generaltexth->allTexts[347]);
|
||||
@@ -168,7 +169,7 @@ void CQuestLog::recreateLabelList()
|
||||
text.replaceRawString(toSeer.toString());
|
||||
}
|
||||
else
|
||||
text.replaceRawString(quests[i].obj->getObjectName()); //get name of the object
|
||||
text.replaceRawString(questObject->getObjectName()); //get name of the object
|
||||
}
|
||||
auto label = std::make_shared<CQuestLabel>(Rect(13, 195, 149,31), FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, text.toString());
|
||||
label->disable();
|
||||
@@ -177,7 +178,7 @@ void CQuestLog::recreateLabelList()
|
||||
labels.push_back(label);
|
||||
|
||||
// Select latest active quest
|
||||
if(!quests[i].quest->isCompleted)
|
||||
if(!questPtr->isCompleted)
|
||||
selectQuest(i, currentLabel);
|
||||
|
||||
currentLabel = static_cast<int>(labels.size());
|
||||
@@ -233,7 +234,7 @@ void CQuestLog::selectQuest(int which, int labelId)
|
||||
|
||||
MetaString text;
|
||||
std::vector<Component> components;
|
||||
currentQuest->quest->getVisitText(currentQuest->obj->cb, text, components, true);
|
||||
currentQuest->getQuest(GAME->interface()->cb.get())->getVisitText(GAME->interface()->cb.get(), text, components, true);
|
||||
if(description->slider)
|
||||
description->slider->scrollToMin(); // scroll text to start position
|
||||
description->setText(text.toString()); //TODO: use special log entry text
|
||||
|
@@ -107,6 +107,7 @@ set(lib_MAIN_SRCS
|
||||
gameState/CGameStateCampaign.cpp
|
||||
gameState/HighScore.cpp
|
||||
gameState/InfoAboutArmy.cpp
|
||||
gameState/QuestInfo.cpp
|
||||
gameState/RumorState.cpp
|
||||
gameState/TavernHeroesPool.cpp
|
||||
gameState/GameStatistics.cpp
|
||||
|
@@ -78,8 +78,8 @@ public:
|
||||
void pickAllowedArtsSet(std::vector<ArtifactID> & out, vstd::RNG & rand);
|
||||
void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt);
|
||||
|
||||
void saveCommonState(CSaveFile &out) const; //stores GS and LIBRARY
|
||||
void loadCommonState(CLoadFile &in); //loads GS and LIBRARY
|
||||
void saveCommonState(CSaveFile &out) const; //stores GS
|
||||
void loadCommonState(CLoadFile &in); //loads GS
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IGameEventCallback
|
||||
|
@@ -66,6 +66,7 @@ public:
|
||||
using StaticIdentifier<BattleID>::StaticIdentifier;
|
||||
DLL_LINKAGE static const BattleID NONE;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ObjectInstanceID : public StaticIdentifier<ObjectInstanceID>
|
||||
{
|
||||
public:
|
||||
@@ -76,6 +77,16 @@ public:
|
||||
static std::string encode(const si32 index);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE QuestInstanceID : public StaticIdentifier<QuestInstanceID>
|
||||
{
|
||||
public:
|
||||
using StaticIdentifier<QuestInstanceID>::StaticIdentifier;
|
||||
static const QuestInstanceID NONE;
|
||||
|
||||
static si32 decode(const std::string & identifier);
|
||||
static std::string encode(const si32 index);
|
||||
};
|
||||
|
||||
class HeroClassID : public EntityIdentifier<HeroClassID>
|
||||
{
|
||||
public:
|
||||
|
36
lib/gameState/QuestInfo.cpp
Normal file
36
lib/gameState/QuestInfo.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QuestInfo.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "QuestInfo.h"
|
||||
|
||||
#include "../mapObjects/CQuest.h"
|
||||
#include "../CGameInfoCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
const CQuest * QuestInfo::getQuest(CGameInfoCallback *cb) const
|
||||
{
|
||||
auto questObject = dynamic_cast<const IQuestObject*>(getObject(cb));
|
||||
assert(questObject);
|
||||
|
||||
return &questObject->getQuest();
|
||||
}
|
||||
|
||||
const CGObjectInstance * QuestInfo::getObject(CGameInfoCallback *cb) const
|
||||
{
|
||||
return cb->getObjInstance(obj);
|
||||
}
|
||||
|
||||
int3 QuestInfo::getPosition(CGameInfoCallback *cb) const
|
||||
{
|
||||
return getObject(cb)->visitablePos();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@@ -10,45 +10,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "int3.h"
|
||||
#include "../constants/EntityIdentifiers.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CQuest;
|
||||
class CGObjectInstance;
|
||||
class CGameInfoCallback;
|
||||
|
||||
struct DLL_LINKAGE QuestInfo //universal interface for human and AI
|
||||
{
|
||||
const CQuest * quest;
|
||||
const CGObjectInstance * obj; //related object, most likely Seer Hut
|
||||
int3 tile;
|
||||
ObjectInstanceID obj; //related object, Seer Hut or Border Guard
|
||||
|
||||
QuestInfo()
|
||||
: quest(nullptr), obj(nullptr), tile(-1,-1,-1)
|
||||
{};
|
||||
QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) :
|
||||
quest (Quest), obj (Obj), tile (Tile){};
|
||||
QuestInfo() = default;
|
||||
explicit QuestInfo(ObjectInstanceID Obj)
|
||||
: obj(Obj)
|
||||
{}
|
||||
|
||||
QuestInfo (const QuestInfo &qi) : quest(qi.quest), obj(qi.obj), tile(qi.tile)
|
||||
{};
|
||||
|
||||
const QuestInfo& operator= (const QuestInfo &qi)
|
||||
{
|
||||
quest = qi.quest;
|
||||
obj = qi.obj;
|
||||
tile = qi.tile;
|
||||
return *this;
|
||||
}
|
||||
const CQuest * getQuest(CGameInfoCallback *cb) const;
|
||||
const CGObjectInstance * getObject(CGameInfoCallback *cb) const;
|
||||
int3 getPosition(CGameInfoCallback *cb) const;
|
||||
|
||||
bool operator== (const QuestInfo & qi) const
|
||||
{
|
||||
return (quest == qi.quest && obj == qi.obj);
|
||||
return obj == qi.obj;
|
||||
}
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & quest;
|
||||
//h & quest;
|
||||
h & obj;
|
||||
h & tile;
|
||||
//h & tile;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -178,7 +178,7 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
|
||||
cb->giveResources(h->getOwner(), -mission.resources);
|
||||
}
|
||||
|
||||
void CQuest::addTextReplacements(IGameCallback * cb, MetaString & text, std::vector<Component> & components) const
|
||||
void CQuest::addTextReplacements(const CGameInfoCallback * cb, MetaString & text, std::vector<Component> & components) const
|
||||
{
|
||||
if(mission.heroLevel > 0)
|
||||
text.replaceNumber(mission.heroLevel);
|
||||
@@ -277,7 +277,7 @@ void CQuest::addTextReplacements(IGameCallback * cb, MetaString & text, std::vec
|
||||
text.replaceNumber(lastDay - cb->getDate(Date::DAY));
|
||||
}
|
||||
|
||||
void CQuest::getVisitText(IGameCallback * cb, MetaString &iwText, std::vector<Component> &components, bool firstVisit, const CGHeroInstance * h) const
|
||||
void CQuest::getVisitText(const CGameInfoCallback * cb, MetaString &iwText, std::vector<Component> &components, bool firstVisit, const CGHeroInstance * h) const
|
||||
{
|
||||
bool failRequirements = (h ? !checkQuest(h) : true);
|
||||
mission.loadComponents(components, h);
|
||||
@@ -293,7 +293,7 @@ void CQuest::getVisitText(IGameCallback * cb, MetaString &iwText, std::vector<Co
|
||||
addTextReplacements(cb, iwText, components);
|
||||
}
|
||||
|
||||
void CQuest::getRolloverText(IGameCallback * cb, MetaString &ms, bool onHover) const
|
||||
void CQuest::getRolloverText(const CGameInfoCallback * cb, MetaString &ms, bool onHover) const
|
||||
{
|
||||
if(onHover)
|
||||
ms.appendRawString("\n\n");
|
||||
@@ -306,7 +306,7 @@ void CQuest::getRolloverText(IGameCallback * cb, MetaString &ms, bool onHover) c
|
||||
addTextReplacements(cb, ms, components);
|
||||
}
|
||||
|
||||
void CQuest::getCompletionText(IGameCallback * cb, MetaString &iwText) const
|
||||
void CQuest::getCompletionText(const CGameInfoCallback * cb, MetaString &iwText) const
|
||||
{
|
||||
iwText.appendRawString(completedText.toString());
|
||||
|
||||
@@ -415,36 +415,37 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi
|
||||
|
||||
}
|
||||
|
||||
IQuestObject::IQuestObject()
|
||||
:quest(std::make_unique<CQuest>())
|
||||
{}
|
||||
|
||||
IQuestObject::~IQuestObject() = default;
|
||||
|
||||
bool IQuestObject::checkQuest(const CGHeroInstance* h) const
|
||||
{
|
||||
return quest->checkQuest(h);
|
||||
return getQuest().checkQuest(h);
|
||||
}
|
||||
|
||||
void CGSeerHut::getVisitText(MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h) const
|
||||
{
|
||||
quest->getVisitText(cb, text, components, FirstVisit, h);
|
||||
}
|
||||
|
||||
void IQuestObject::afterAddToMapCommon(CMap * map) const
|
||||
{
|
||||
map->addNewQuestInstance(quest);
|
||||
getQuest().getVisitText(cb, text, components, FirstVisit, h);
|
||||
}
|
||||
|
||||
void CGSeerHut::setObjToKill()
|
||||
{
|
||||
if(quest->killTarget == ObjectInstanceID::NONE)
|
||||
if(getQuest().killTarget == ObjectInstanceID::NONE)
|
||||
return;
|
||||
|
||||
if(getCreatureToKill(true))
|
||||
{
|
||||
quest->stackToKill = getCreatureToKill(false)->getCreatureID();
|
||||
assert(quest->stackToKill != CreatureID::NONE);
|
||||
quest->stackDirection = checkDirection();
|
||||
getQuest().stackToKill = getCreatureToKill(false)->getCreatureID();
|
||||
assert(getQuest().stackToKill != CreatureID::NONE);
|
||||
getQuest().stackDirection = checkDirection();
|
||||
}
|
||||
else if(getHeroToKill(true))
|
||||
{
|
||||
quest->heroName = getHeroToKill(false)->getNameTranslated();
|
||||
quest->heroPortrait = getHeroToKill(false)->getPortraitSource();
|
||||
getQuest().heroName = getHeroToKill(false)->getNameTranslated();
|
||||
getQuest().heroPortrait = getHeroToKill(false)->getPortraitSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,8 +455,8 @@ void CGSeerHut::init(vstd::RNG & rand)
|
||||
|
||||
auto seerNameID = *RandomGeneratorUtil::nextItem(names, rand);
|
||||
seerName = LIBRARY->generaltexth->translate(seerNameID);
|
||||
quest->textOption = rand.nextInt(2);
|
||||
quest->completedOption = rand.nextInt(1, 3);
|
||||
getQuest().textOption = rand.nextInt(2);
|
||||
getQuest().completedOption = rand.nextInt(1, 3);
|
||||
|
||||
configuration.canRefuse = true;
|
||||
configuration.visitMode = Rewardable::EVisitMode::VISIT_ONCE;
|
||||
@@ -469,33 +470,33 @@ void CGSeerHut::initObj(vstd::RNG & rand)
|
||||
CRewardableObject::initObj(rand);
|
||||
|
||||
setObjToKill();
|
||||
quest->defineQuestName();
|
||||
getQuest().defineQuestName();
|
||||
|
||||
if(quest->mission == Rewardable::Limiter{} && quest->killTarget == ObjectInstanceID::NONE)
|
||||
quest->isCompleted = true;
|
||||
if(getQuest().mission == Rewardable::Limiter{} && getQuest().killTarget == ObjectInstanceID::NONE)
|
||||
getQuest().isCompleted = true;
|
||||
|
||||
if(quest->questName == quest->missionName(EQuestMission::NONE))
|
||||
if(getQuest().questName == getQuest().missionName(EQuestMission::NONE))
|
||||
{
|
||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seehut", "empty", quest->completedOption).get());
|
||||
getQuest().firstVisitText.appendTextID(TextIdentifier("core", "seehut", "empty", getQuest().completedOption).get());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!quest->isCustomFirst)
|
||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", quest->questName, quest->missionState(0), quest->textOption).get());
|
||||
if(!quest->isCustomNext)
|
||||
quest->nextVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", quest->questName, quest->missionState(1), quest->textOption).get());
|
||||
if(!quest->isCustomComplete)
|
||||
quest->completedText.appendTextID(TextIdentifier("core", "seerhut", "quest", quest-> questName, quest->missionState(2), quest->textOption).get());
|
||||
if(!getQuest().isCustomFirst)
|
||||
getQuest().firstVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", getQuest().questName, getQuest().missionState(0), getQuest().textOption).get());
|
||||
if(!getQuest().isCustomNext)
|
||||
getQuest().nextVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", getQuest().questName, getQuest().missionState(1), getQuest().textOption).get());
|
||||
if(!getQuest().isCustomComplete)
|
||||
getQuest().completedText.appendTextID(TextIdentifier("core", "seerhut", "quest", getQuest(). questName, getQuest().missionState(2), getQuest().textOption).get());
|
||||
}
|
||||
|
||||
quest->getCompletionText(cb, configuration.onSelect);
|
||||
getQuest().getCompletionText(cb, configuration.onSelect);
|
||||
for(auto & i : configuration.info)
|
||||
quest->getCompletionText(cb, i.message);
|
||||
getQuest().getCompletionText(cb, i.message);
|
||||
}
|
||||
|
||||
void CGSeerHut::getRolloverText(MetaString &text, bool onHover) const
|
||||
{
|
||||
quest->getRolloverText(cb, text, onHover);//TODO: simplify?
|
||||
getQuest().getRolloverText(cb, text, onHover);//TODO: simplify?
|
||||
if(!onHover)
|
||||
text.replaceRawString(seerName);
|
||||
}
|
||||
@@ -503,15 +504,15 @@ void CGSeerHut::getRolloverText(MetaString &text, bool onHover) const
|
||||
std::string CGSeerHut::getHoverText(PlayerColor player) const
|
||||
{
|
||||
std::string hoverName = getObjectName();
|
||||
if(ID == Obj::SEER_HUT && quest->activeForPlayers.count(player))
|
||||
if(ID == Obj::SEER_HUT && getQuest().activeForPlayers.count(player))
|
||||
{
|
||||
hoverName = LIBRARY->generaltexth->allTexts[347];
|
||||
boost::algorithm::replace_first(hoverName, "%s", seerName);
|
||||
}
|
||||
|
||||
if(quest->activeForPlayers.count(player)
|
||||
&& (quest->mission != Rewardable::Limiter{}
|
||||
|| quest->killTarget != ObjectInstanceID::NONE)) //rollover when the quest is active
|
||||
if(getQuest().activeForPlayers.count(player)
|
||||
&& (getQuest().mission != Rewardable::Limiter{}
|
||||
|| getQuest().killTarget != ObjectInstanceID::NONE)) //rollover when the quest is active
|
||||
{
|
||||
MetaString ms;
|
||||
getRolloverText (ms, true);
|
||||
@@ -538,16 +539,16 @@ std::string CGSeerHut::getPopupText(const CGHeroInstance * hero) const
|
||||
std::vector<Component> CGSeerHut::getPopupComponents(PlayerColor player) const
|
||||
{
|
||||
std::vector<Component> result;
|
||||
if (quest->activeForPlayers.count(player))
|
||||
quest->mission.loadComponents(result, nullptr);
|
||||
if (getQuest().activeForPlayers.count(player))
|
||||
getQuest().mission.loadComponents(result, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Component> CGSeerHut::getPopupComponents(const CGHeroInstance * hero) const
|
||||
{
|
||||
std::vector<Component> result;
|
||||
if (quest->activeForPlayers.count(hero->getOwner()))
|
||||
quest->mission.loadComponents(result, hero);
|
||||
if (getQuest().activeForPlayers.count(hero->getOwner()))
|
||||
getQuest().mission.loadComponents(result, hero);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -557,13 +558,13 @@ void CGSeerHut::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
||||
{
|
||||
case ObjProperty::SEERHUT_VISITED:
|
||||
{
|
||||
quest->activeForPlayers.emplace(identifier.as<PlayerColor>());
|
||||
getQuest().activeForPlayers.emplace(identifier.as<PlayerColor>());
|
||||
break;
|
||||
}
|
||||
case ObjProperty::SEERHUT_COMPLETE:
|
||||
{
|
||||
quest->isCompleted = identifier.getNum();
|
||||
quest->activeForPlayers.clear();
|
||||
getQuest().isCompleted = identifier.getNum();
|
||||
getQuest().activeForPlayers.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -572,7 +573,7 @@ void CGSeerHut::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
||||
void CGSeerHut::newTurn(vstd::RNG & rand) const
|
||||
{
|
||||
CRewardableObject::newTurn(rand);
|
||||
if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up
|
||||
if(getQuest().lastDay >= 0 && getQuest().lastDay <= cb->getDate() - 1) //time is up
|
||||
{
|
||||
cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, true);
|
||||
}
|
||||
@@ -582,9 +583,9 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = h->getOwner();
|
||||
if(!quest->isCompleted)
|
||||
if(!getQuest().isCompleted)
|
||||
{
|
||||
bool firstVisit = !quest->activeForPlayers.count(h->getOwner());
|
||||
bool firstVisit = !getQuest().activeForPlayers.count(h->getOwner());
|
||||
bool failRequirements = !checkQuest(h);
|
||||
|
||||
if(firstVisit)
|
||||
@@ -592,7 +593,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
||||
cb->setObjPropertyID(id, ObjProperty::SEERHUT_VISITED, h->getOwner());
|
||||
|
||||
AddQuest aq;
|
||||
aq.quest = QuestInfo(quest.get(), this, visitablePos());
|
||||
aq.quest = QuestInfo(id);
|
||||
aq.player = h->tempOwner;
|
||||
cb->sendAndApply(aq); //TODO: merge with setObjProperty?
|
||||
}
|
||||
@@ -611,7 +612,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
||||
}
|
||||
else
|
||||
{
|
||||
iw.text.appendRawString(LIBRARY->generaltexth->seerEmpty[quest->completedOption]);
|
||||
iw.text.appendRawString(LIBRARY->generaltexth->seerEmpty[getQuest().completedOption]);
|
||||
if (ID == Obj::SEER_HUT)
|
||||
iw.text.replaceRawString(seerName);
|
||||
cb->showInfoDialog(&iw);
|
||||
@@ -652,7 +653,7 @@ int CGSeerHut::checkDirection() const
|
||||
|
||||
const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
|
||||
{
|
||||
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||
const CGObjectInstance *o = cb->getObj(getQuest().killTarget);
|
||||
if(allowNull && !o)
|
||||
return nullptr;
|
||||
return dynamic_cast<const CGHeroInstance *>(o);
|
||||
@@ -660,7 +661,7 @@ const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
|
||||
|
||||
const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
|
||||
{
|
||||
const CGObjectInstance *o = cb->getObj(quest->killTarget);
|
||||
const CGObjectInstance *o = cb->getObj(getQuest().killTarget);
|
||||
if(allowNull && !o)
|
||||
return nullptr;
|
||||
return dynamic_cast<const CGCreature *>(o);
|
||||
@@ -671,21 +672,16 @@ void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answe
|
||||
CRewardableObject::blockingDialogAnswered(hero, answer);
|
||||
if(answer)
|
||||
{
|
||||
quest->completeQuest(cb, hero);
|
||||
cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, !quest->repeatedQuest); //mission complete
|
||||
getQuest().completeQuest(cb, hero);
|
||||
cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, !getQuest().repeatedQuest); //mission complete
|
||||
}
|
||||
}
|
||||
|
||||
void CGSeerHut::afterAddToMap(CMap* map)
|
||||
{
|
||||
IQuestObject::afterAddToMapCommon(map);
|
||||
}
|
||||
|
||||
void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
//quest and reward
|
||||
CRewardableObject::serializeJsonOptions(handler);
|
||||
quest->serializeJson(handler, "quest");
|
||||
getQuest().serializeJson(handler, "quest");
|
||||
|
||||
if(!handler.saving)
|
||||
{
|
||||
@@ -760,8 +756,8 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
void CGQuestGuard::init(vstd::RNG & rand)
|
||||
{
|
||||
blockVisit = true;
|
||||
quest->textOption = rand.nextInt(3, 5);
|
||||
quest->completedOption = rand.nextInt(4, 5);
|
||||
getQuest().textOption = rand.nextInt(3, 5);
|
||||
getQuest().completedOption = rand.nextInt(4, 5);
|
||||
|
||||
configuration.info.push_back({});
|
||||
configuration.info.back().visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
||||
@@ -771,7 +767,7 @@ void CGQuestGuard::init(vstd::RNG & rand)
|
||||
|
||||
void CGQuestGuard::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
if(!quest->isCompleted)
|
||||
if(!getQuest().isCompleted)
|
||||
CGSeerHut::onHeroVisit(h);
|
||||
else
|
||||
cb->setObjPropertyValue(id, ObjProperty::SEERHUT_COMPLETE, false);
|
||||
@@ -779,13 +775,13 @@ void CGQuestGuard::onHeroVisit(const CGHeroInstance * h) const
|
||||
|
||||
bool CGQuestGuard::passableFor(PlayerColor color) const
|
||||
{
|
||||
return quest->isCompleted;
|
||||
return getQuest().isCompleted;
|
||||
}
|
||||
|
||||
void CGQuestGuard::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
//quest only, do not call base class
|
||||
quest->serializeJson(handler, "quest");
|
||||
getQuest().serializeJson(handler, "quest");
|
||||
}
|
||||
|
||||
bool CGKeys::wasMyColorVisited(const PlayerColor & player) const
|
||||
@@ -869,7 +865,7 @@ void CGBorderGuard::onHeroVisit(const CGHeroInstance * h) const
|
||||
h->showInfoDialog(18);
|
||||
|
||||
AddQuest aq;
|
||||
aq.quest = QuestInfo (quest.get(), this, visitablePos());
|
||||
aq.quest = QuestInfo(id);
|
||||
aq.player = h->tempOwner;
|
||||
cb->sendAndApply(aq);
|
||||
//TODO: add this quest only once OR check for multiple instances later
|
||||
@@ -882,11 +878,6 @@ void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, int32_t a
|
||||
cb->removeObject(this, hero->getOwner());
|
||||
}
|
||||
|
||||
void CGBorderGuard::afterAddToMap(CMap * map)
|
||||
{
|
||||
IQuestObject::afterAddToMapCommon(map);
|
||||
}
|
||||
|
||||
void CGBorderGate::onHeroVisit(const CGHeroInstance * h) const //TODO: passability
|
||||
{
|
||||
if (!wasMyColorVisited (h->getOwner()) )
|
||||
@@ -894,7 +885,7 @@ void CGBorderGate::onHeroVisit(const CGHeroInstance * h) const //TODO: passabili
|
||||
h->showInfoDialog(18);
|
||||
|
||||
AddQuest aq;
|
||||
aq.quest = QuestInfo (quest.get(), this, visitablePos());
|
||||
aq.quest = QuestInfo(id);
|
||||
aq.player = h->tempOwner;
|
||||
cb->sendAndApply(aq);
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
std::string questName;
|
||||
|
||||
si32 qid; //unique quest id for serialization / identification
|
||||
QuestInstanceID qid;
|
||||
|
||||
si32 lastDay; //after this day (first day is 0) mission cannot be completed; if -1 - no limit
|
||||
ObjectInstanceID killTarget;
|
||||
@@ -77,11 +77,11 @@ public:
|
||||
|
||||
static bool checkMissionArmy(const CQuest * q, const CCreatureSet * army);
|
||||
bool checkQuest(const CGHeroInstance * h) const; //determines whether the quest is complete or not
|
||||
void getVisitText(IGameCallback * cb, MetaString &text, std::vector<Component> & components, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
||||
void getCompletionText(IGameCallback * cb, MetaString &text) const;
|
||||
void getRolloverText (IGameCallback * cb, MetaString &text, bool onHover) const; //hover or quest log entry
|
||||
void getVisitText(const CGameInfoCallback * cb, MetaString &text, std::vector<Component> & components, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
||||
void getCompletionText(const CGameInfoCallback * cb, MetaString &text) const;
|
||||
void getRolloverText (const CGameInfoCallback * cb, MetaString &text, bool onHover) const; //hover or quest log entry
|
||||
void completeQuest(IGameCallback *, const CGHeroInstance * h) const;
|
||||
void addTextReplacements(IGameCallback * cb, MetaString &out, std::vector<Component> & components) const;
|
||||
void addTextReplacements(const CGameInfoCallback * cb, MetaString &out, std::vector<Component> & components) const;
|
||||
void addKillTargetReplacements(MetaString &out) const;
|
||||
void defineQuestName();
|
||||
|
||||
@@ -116,34 +116,21 @@ public:
|
||||
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IQuestObject : public virtual Serializeable
|
||||
class DLL_LINKAGE IQuestObject
|
||||
{
|
||||
friend class CMapLoaderH3M;
|
||||
friend class TreasurePlacer; // RMG
|
||||
friend class Inspector; // Map editor
|
||||
|
||||
protected:
|
||||
std::shared_ptr<CQuest> quest;
|
||||
|
||||
std::unique_ptr<CQuest> quest;
|
||||
public:
|
||||
IQuestObject()
|
||||
:quest(std::make_shared<CQuest>())
|
||||
{}
|
||||
|
||||
virtual ~IQuestObject() = default;
|
||||
IQuestObject();
|
||||
virtual ~IQuestObject();
|
||||
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h = nullptr) const = 0;
|
||||
virtual bool checkQuest (const CGHeroInstance * h) const;
|
||||
const CQuest * getQuest() const
|
||||
{
|
||||
return quest.get();
|
||||
}
|
||||
virtual const CQuest & getQuest() const { return *quest; }
|
||||
virtual CQuest & getQuest() { return *quest; }
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & quest;
|
||||
}
|
||||
protected:
|
||||
void afterAddToMapCommon(CMap * map) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGSeerHut : public CRewardableObject, public IQuestObject
|
||||
@@ -172,8 +159,6 @@ public:
|
||||
const CGCreature *getCreatureToKill(bool allowNull) const;
|
||||
void getRolloverText (MetaString &text, bool onHover) const;
|
||||
|
||||
void afterAddToMap(CMap * map) override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & static_cast<CRewardableObject&>(*this);
|
||||
@@ -237,6 +222,7 @@ public:
|
||||
|
||||
class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject
|
||||
{
|
||||
QuestInstanceID qid;
|
||||
public:
|
||||
using CGKeys::CGKeys;
|
||||
|
||||
@@ -248,8 +234,6 @@ public:
|
||||
void getRolloverText (MetaString &text, bool onHover) const;
|
||||
bool checkQuest (const CGHeroInstance * h) const override;
|
||||
|
||||
void afterAddToMap(CMap * map) override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & static_cast<IQuestObject&>(*this);
|
||||
@@ -265,11 +249,6 @@ public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
|
||||
bool passableFor(PlayerColor color) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & static_cast<CGBorderGuard&>(*this); //need to serialize or object will be empty
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -497,19 +497,6 @@ void CMap::removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & s
|
||||
artifact->addPlacementMap(partsMap);
|
||||
}
|
||||
|
||||
void CMap::addNewQuestInstance(std::shared_ptr<CQuest> quest)
|
||||
{
|
||||
quest->qid = static_cast<si32>(quests.size());
|
||||
quests.emplace_back(quest);
|
||||
}
|
||||
|
||||
void CMap::clearQuestInstance(const CQuest * quest)
|
||||
{
|
||||
assert(quests.at(quest->qid).get() == quest);
|
||||
|
||||
quests.at(quest->qid) = nullptr;
|
||||
}
|
||||
|
||||
void CMap::generateUniqueInstanceName(CGObjectInstance * target)
|
||||
{
|
||||
//this gives object unique name even if objects are removed later
|
||||
@@ -727,17 +714,6 @@ CMapEditManager * CMap::getEditManager()
|
||||
return editManager.get();
|
||||
}
|
||||
|
||||
void CMap::resolveQuestIdentifiers()
|
||||
{
|
||||
//FIXME: move to CMapLoaderH3M
|
||||
for (auto & quest : quests)
|
||||
{
|
||||
if (quest && quest->killTarget != ObjectInstanceID::NONE)
|
||||
quest->killTarget = questIdentifierToId[quest->killTarget.getNum()];
|
||||
}
|
||||
questIdentifierToId.clear();
|
||||
}
|
||||
|
||||
void CMap::reindexObjects()
|
||||
{
|
||||
// Only reindex at editor / RMG operations
|
||||
|
@@ -62,8 +62,6 @@ class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
|
||||
|
||||
std::unique_ptr<GameSettings> gameSettings;
|
||||
|
||||
/// All quests that are currently present on map
|
||||
std::vector<std::shared_ptr<CQuest>> quests;
|
||||
/// All artifacts that exists on map, whether on map, in hero inventory, or stored in some object
|
||||
std::vector<std::shared_ptr<CArtifactInstance>> artInstances;
|
||||
/// All heroes that are currently free for recruitment in taverns and are not present on map
|
||||
@@ -78,7 +76,7 @@ class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
|
||||
public:
|
||||
/// Central lists of items in game. Position of item in the vectors below is their (instance) id.
|
||||
/// TODO: make private
|
||||
std::vector< std::shared_ptr<CGObjectInstance> > objects;
|
||||
std::vector<std::shared_ptr<CGObjectInstance>> objects;
|
||||
|
||||
explicit CMap(IGameCallback *cb);
|
||||
~CMap();
|
||||
@@ -110,9 +108,6 @@ public:
|
||||
void putArtifactInstance(CArtifactSet & set, const ArtifactInstanceID art, const ArtifactPosition & slot);
|
||||
void removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot);
|
||||
|
||||
void addNewQuestInstance(std::shared_ptr<CQuest> quest);
|
||||
void clearQuestInstance(const CQuest * quest);
|
||||
|
||||
void generateUniqueInstanceName(CGObjectInstance * target);
|
||||
|
||||
///Use only this method when creating new map object instances
|
||||
@@ -213,8 +208,6 @@ public:
|
||||
//Helper lists
|
||||
std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > teleportChannels;
|
||||
|
||||
/// associative list to identify which hero/creature id belongs to which object id(index for objects)
|
||||
std::map<si32, ObjectInstanceID> questIdentifierToId;
|
||||
|
||||
std::unique_ptr<CMapEditManager> editManager;
|
||||
boost::multi_array<int3, 3> guardingCreaturePositions;
|
||||
@@ -254,7 +247,6 @@ public:
|
||||
h & events;
|
||||
h & grailPos;
|
||||
h & artInstances;
|
||||
h & quests;
|
||||
|
||||
//TODO: viccondetails
|
||||
h & terrain;
|
||||
|
@@ -1186,7 +1186,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readMonster(const int3 & mapPos
|
||||
if(features.levelAB)
|
||||
{
|
||||
object->identifier = reader->readUInt32();
|
||||
map->questIdentifierToId[object->identifier] = objectInstanceID;
|
||||
questIdentifierToId[object->identifier] = objectInstanceID;
|
||||
}
|
||||
|
||||
auto hlp = std::make_unique<CStackInstance>();
|
||||
@@ -2035,7 +2035,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readHero(const int3 & mapPositi
|
||||
if(features.levelAB)
|
||||
{
|
||||
unsigned int identifier = reader->readUInt32();
|
||||
map->questIdentifierToId[identifier] = objectInstanceID;
|
||||
questIdentifierToId[identifier] = objectInstanceID;
|
||||
}
|
||||
|
||||
PlayerColor owner = reader->readPlayer();
|
||||
@@ -2224,7 +2224,7 @@ std::shared_ptr<CGObjectInstance> CMapLoaderH3M::readSeerHut(const int3 & positi
|
||||
if(features.levelHOTA3)
|
||||
{
|
||||
uint32_t repeateableQuestsCount = reader->readUInt32();
|
||||
hut->quest->repeatedQuest = repeateableQuestsCount != 0;
|
||||
hut->getQuest().repeatedQuest = repeateableQuestsCount != 0;
|
||||
|
||||
if(repeateableQuestsCount != 0)
|
||||
logGlobal->warn("Map '%s': Seer Hut at %s - %d repeatable quests are not implemented!", mapName, position.toString(), repeateableQuestsCount);
|
||||
@@ -2267,13 +2267,13 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
||||
if(artID != ArtifactID::NONE)
|
||||
{
|
||||
//not none quest
|
||||
hut->quest->mission.artifacts.push_back(artID);
|
||||
hut->getQuest().mission.artifacts.push_back(artID);
|
||||
missionType = EQuestMission::ARTIFACT;
|
||||
}
|
||||
hut->quest->lastDay = -1; //no timeout
|
||||
hut->quest->isCustomFirst = false;
|
||||
hut->quest->isCustomNext = false;
|
||||
hut->quest->isCustomComplete = false;
|
||||
hut->getQuest().lastDay = -1; //no timeout
|
||||
hut->getQuest().isCustomFirst = false;
|
||||
hut->getQuest().isCustomNext = false;
|
||||
hut->getQuest().isCustomComplete = false;
|
||||
}
|
||||
|
||||
if(missionType != EQuestMission::NONE)
|
||||
@@ -2386,19 +2386,20 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
{
|
||||
for(int x = 0; x < 4; ++x)
|
||||
{
|
||||
guard->quest->mission.primary[x] = reader->readUInt8();
|
||||
guard->getQuest().mission.primary[x] = reader->readUInt8();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EQuestMission::LEVEL:
|
||||
{
|
||||
guard->quest->mission.heroLevel = reader->readUInt32();
|
||||
guard->getQuest().mission.heroLevel = reader->readUInt32();
|
||||
break;
|
||||
}
|
||||
case EQuestMission::KILL_HERO:
|
||||
case EQuestMission::KILL_CREATURE:
|
||||
{
|
||||
guard->quest->killTarget = ObjectInstanceID(reader->readUInt32());
|
||||
assert(questsToResolve.count(guard) == 0);
|
||||
questsToResolve[guard] = reader->readUInt32();
|
||||
break;
|
||||
}
|
||||
case EQuestMission::ARTIFACT:
|
||||
@@ -2414,7 +2415,7 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
logGlobal->warn("Map '%s': Seer Hut at %s: Quest to find scroll '%s' is not implemented!", mapName, position.toString(), scrollSpell.toEntity(LIBRARY)->getJsonKey());
|
||||
|
||||
}
|
||||
guard->quest->mission.artifacts.push_back(artid);
|
||||
guard->getQuest().mission.artifacts.push_back(artid);
|
||||
map->allowedArtifact.erase(artid); //these are unavailable for random generation
|
||||
}
|
||||
break;
|
||||
@@ -2422,29 +2423,29 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
case EQuestMission::ARMY:
|
||||
{
|
||||
size_t typeNumber = reader->readUInt8();
|
||||
guard->quest->mission.creatures.resize(typeNumber);
|
||||
guard->getQuest().mission.creatures.resize(typeNumber);
|
||||
for(size_t hh = 0; hh < typeNumber; ++hh)
|
||||
{
|
||||
guard->quest->mission.creatures[hh].setType(reader->readCreature().toCreature());
|
||||
guard->quest->mission.creatures[hh].count = reader->readUInt16();
|
||||
guard->getQuest().mission.creatures[hh].setType(reader->readCreature().toCreature());
|
||||
guard->getQuest().mission.creatures[hh].count = reader->readUInt16();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EQuestMission::RESOURCES:
|
||||
{
|
||||
for(int x = 0; x < 7; ++x)
|
||||
guard->quest->mission.resources[x] = reader->readUInt32();
|
||||
guard->getQuest().mission.resources[x] = reader->readUInt32();
|
||||
|
||||
break;
|
||||
}
|
||||
case EQuestMission::HERO:
|
||||
{
|
||||
guard->quest->mission.heroes.push_back(reader->readHero());
|
||||
guard->getQuest().mission.heroes.push_back(reader->readHero());
|
||||
break;
|
||||
}
|
||||
case EQuestMission::PLAYER:
|
||||
{
|
||||
guard->quest->mission.players.push_back(reader->readPlayer());
|
||||
guard->getQuest().mission.players.push_back(reader->readPlayer());
|
||||
break;
|
||||
}
|
||||
case EQuestMission::HOTA_MULTI:
|
||||
@@ -2458,13 +2459,13 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
std::set<HeroClassID> heroClasses;
|
||||
reader->readBitmaskHeroClassesSized(heroClasses, false);
|
||||
for(auto & hc : heroClasses)
|
||||
guard->quest->mission.heroClasses.push_back(hc);
|
||||
guard->getQuest().mission.heroClasses.push_back(hc);
|
||||
break;
|
||||
}
|
||||
if(missionSubID == 1)
|
||||
{
|
||||
missionId = EQuestMission::HOTA_REACH_DATE;
|
||||
guard->quest->mission.daysPassed = reader->readUInt32() + 1;
|
||||
guard->getQuest().mission.daysPassed = reader->readUInt32() + 1;
|
||||
break;
|
||||
}
|
||||
if(missionSubID == 2)
|
||||
@@ -2483,13 +2484,13 @@ EQuestMission CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & positi
|
||||
}
|
||||
}
|
||||
|
||||
guard->quest->lastDay = reader->readInt32();
|
||||
guard->quest->firstVisitText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "firstVisit")));
|
||||
guard->quest->nextVisitText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "nextVisit")));
|
||||
guard->quest->completedText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "completed")));
|
||||
guard->quest->isCustomFirst = !guard->quest->firstVisitText.empty();
|
||||
guard->quest->isCustomNext = !guard->quest->nextVisitText.empty();
|
||||
guard->quest->isCustomComplete = !guard->quest->completedText.empty();
|
||||
guard->getQuest().lastDay = reader->readInt32();
|
||||
guard->getQuest().firstVisitText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "firstVisit")));
|
||||
guard->getQuest().nextVisitText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "nextVisit")));
|
||||
guard->getQuest().completedText.appendTextID(readLocalizedString(TextIdentifier("quest", position.x, position.y, position.z, "completed")));
|
||||
guard->getQuest().isCustomFirst = !guard->getQuest().firstVisitText.empty();
|
||||
guard->getQuest().isCustomNext = !guard->getQuest().nextVisitText.empty();
|
||||
guard->getQuest().isCustomComplete = !guard->getQuest().completedText.empty();
|
||||
return missionId;
|
||||
}
|
||||
|
||||
@@ -2756,7 +2757,8 @@ void CMapLoaderH3M::afterRead()
|
||||
}
|
||||
}
|
||||
|
||||
map->resolveQuestIdentifiers();
|
||||
for (auto & quest : questsToResolve)
|
||||
quest.first->getQuest().killTarget = questIdentifierToId.at(quest.second);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -268,6 +268,10 @@ private:
|
||||
std::vector<std::shared_ptr<ObjectTemplate>> originalTemplates;
|
||||
std::vector<std::shared_ptr<ObjectTemplate>> remappedTemplates;
|
||||
|
||||
/// associative list to identify which hero/creature id belongs to which object id(index for objects)
|
||||
std::map<si32, ObjectInstanceID> questIdentifierToId;
|
||||
std::map<IQuestObject*, si32> questsToResolve;
|
||||
|
||||
/** ptr to the map object which gets filled by data from the buffer */
|
||||
CMap * map;
|
||||
|
||||
|
@@ -77,17 +77,7 @@ si32 MapObjectResolver::decode(const std::string & identifier) const
|
||||
|
||||
std::string MapObjectResolver::encode(si32 identifier) const
|
||||
{
|
||||
ObjectInstanceID id;
|
||||
|
||||
//use h3m questIdentifiers if they are present
|
||||
if(owner->map->questIdentifierToId.empty())
|
||||
{
|
||||
id = ObjectInstanceID(identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = owner->map->questIdentifierToId[identifier];
|
||||
}
|
||||
ObjectInstanceID id(identifier);
|
||||
|
||||
auto object = owner->map->getObject(id);
|
||||
|
||||
|
@@ -1238,11 +1238,10 @@ void RemoveObject::applyGs(CGameState *gs)
|
||||
const auto * quest = dynamic_cast<const IQuestObject *>(obj);
|
||||
if (quest)
|
||||
{
|
||||
gs->getMap().clearQuestInstance(quest->getQuest());
|
||||
for (auto &player : gs->players)
|
||||
{
|
||||
vstd::erase_if(player.second.quests, [obj](const QuestInfo & q){
|
||||
return q.obj == obj;
|
||||
return q.obj == obj->id;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -515,14 +515,14 @@ void TreasurePlacer::addSeerHuts()
|
||||
auto setRandomArtifact = [qap](CGSeerHut * obj)
|
||||
{
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->mission.artifacts.push_back(artid);
|
||||
obj->getQuest().mission.artifacts.push_back(artid);
|
||||
qap->addQuestArtifact(artid);
|
||||
};
|
||||
auto destroyObject = [qap](CGObjectInstance & obj)
|
||||
{
|
||||
auto & seer = dynamic_cast<CGSeerHut &>(obj);
|
||||
// Artifact can be used again
|
||||
ArtifactID artid = seer.getQuest()->mission.artifacts.front();
|
||||
ArtifactID artid = seer.getQuest().mission.artifacts.front();
|
||||
qap->addRandomArtifact(artid);
|
||||
qap->removeQuestArtifact(artid);
|
||||
};
|
||||
|
@@ -27,8 +27,6 @@ void CSerializer::addStdVecItems(CGameState *gs, GameLibrary *lib)
|
||||
[](const CGObjectInstance &obj){ return obj.id; });
|
||||
registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->getMap().artInstances,
|
||||
[](const CArtifactInstance &artInst){ return artInst.getId(); });
|
||||
registerVectoredType<CQuest, si32>(&gs->getMap().quests,
|
||||
[](const CQuest &q){ return q.qid; });
|
||||
|
||||
smartVectorMembersSerialization = true;
|
||||
}
|
||||
|
@@ -456,26 +456,26 @@ void Inspector::updateProperties(CGEvent * o)
|
||||
|
||||
void Inspector::updateProperties(CGSeerHut * o)
|
||||
{
|
||||
if(!o || !o->getQuest()) return;
|
||||
if(!o) return;
|
||||
|
||||
addProperty(QObject::tr("First visit text"), o->getQuest()->firstVisitText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Next visit text"), o->getQuest()->nextVisitText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Completed text"), o->getQuest()->completedText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Repeat quest"), o->getQuest()->repeatedQuest, false);
|
||||
addProperty(QObject::tr("Time limit"), o->getQuest()->lastDay, false);
|
||||
addProperty(QObject::tr("First visit text"), o->getQuest().firstVisitText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Next visit text"), o->getQuest().nextVisitText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Completed text"), o->getQuest().completedText, new MessageDelegate, false);
|
||||
addProperty(QObject::tr("Repeat quest"), o->getQuest().repeatedQuest, false);
|
||||
addProperty(QObject::tr("Time limit"), o->getQuest().lastDay, false);
|
||||
|
||||
{ //Quest
|
||||
auto * delegate = new QuestDelegate(controller, *o->quest);
|
||||
auto * delegate = new QuestDelegate(controller, o->getQuest());
|
||||
addProperty(QObject::tr("Quest"), PropertyEditorPlaceholder(), delegate, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Inspector::updateProperties(CGQuestGuard * o)
|
||||
{
|
||||
if(!o || !o->getQuest()) return;
|
||||
if(!o) return;
|
||||
|
||||
addProperty(QObject::tr("Reward"), PropertyEditorPlaceholder(), nullptr, true);
|
||||
addProperty(QObject::tr("Repeat quest"), o->getQuest()->repeatedQuest, true);
|
||||
addProperty(QObject::tr("Repeat quest"), o->getQuest().repeatedQuest, true);
|
||||
}
|
||||
|
||||
void Inspector::updateProperties()
|
||||
@@ -773,18 +773,18 @@ void Inspector::setProperty(CGSeerHut * o, const QString & key, const QVariant &
|
||||
if(!o) return;
|
||||
|
||||
if(key == QObject::tr("First visit text"))
|
||||
o->quest->firstVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
o->getQuest().firstVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
TextIdentifier("quest", o->instanceName, "firstVisit"), value.toString().toStdString()));
|
||||
if(key == QObject::tr("Next visit text"))
|
||||
o->quest->nextVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
o->getQuest().nextVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
TextIdentifier("quest", o->instanceName, "nextVisit"), value.toString().toStdString()));
|
||||
if(key == QObject::tr("Completed text"))
|
||||
o->quest->completedText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
o->getQuest().completedText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||
TextIdentifier("quest", o->instanceName, "completed"), value.toString().toStdString()));
|
||||
if(key == QObject::tr("Repeat quest"))
|
||||
o->quest->repeatedQuest = value.toBool();
|
||||
o->getQuest().repeatedQuest = value.toBool();
|
||||
if(key == QObject::tr("Time limit"))
|
||||
o->quest->lastDay = value.toString().toInt();
|
||||
o->getQuest().lastDay = value.toString().toInt();
|
||||
}
|
||||
|
||||
void Inspector::setProperty(CGQuestGuard * o, const QString & key, const QVariant & value)
|
||||
|
Reference in New Issue
Block a user