mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
@@ -38,41 +38,28 @@ TGoalVec CompleteQuest::decompose() const
|
|||||||
|
|
||||||
logAi->debug("Trying to realize quest: %s", questToString());
|
logAi->debug("Trying to realize quest: %s", questToString());
|
||||||
|
|
||||||
switch(q.quest->missionType)
|
if(!q.quest->mission.artifacts.empty())
|
||||||
{
|
|
||||||
case CQuest::MISSION_ART:
|
|
||||||
return missionArt();
|
return missionArt();
|
||||||
|
|
||||||
case CQuest::MISSION_HERO:
|
if(!q.quest->mission.heroes.empty())
|
||||||
return missionHero();
|
return missionHero();
|
||||||
|
|
||||||
case CQuest::MISSION_ARMY:
|
if(!q.quest->mission.creatures.empty())
|
||||||
return missionArmy();
|
return missionArmy();
|
||||||
|
|
||||||
case CQuest::MISSION_RESOURCES:
|
if(q.quest->mission.resources.nonZero())
|
||||||
return missionResources();
|
return missionResources();
|
||||||
|
|
||||||
case CQuest::MISSION_KILL_HERO:
|
if(q.quest->killTarget != ObjectInstanceID::NONE)
|
||||||
case CQuest::MISSION_KILL_CREATURE:
|
|
||||||
return missionDestroyObj();
|
return missionDestroyObj();
|
||||||
|
|
||||||
case CQuest::MISSION_PRIMARY_STAT:
|
for(auto & s : q.quest->mission.primary)
|
||||||
return missionIncreasePrimaryStat();
|
if(s)
|
||||||
|
return missionIncreasePrimaryStat();
|
||||||
|
|
||||||
case CQuest::MISSION_LEVEL:
|
if(q.quest->mission.heroLevel > 0)
|
||||||
return missionLevel();
|
return missionLevel();
|
||||||
|
|
||||||
case CQuest::MISSION_PLAYER:
|
|
||||||
if(ai->playerID.getNum() != q.quest->m13489val)
|
|
||||||
logAi->debug("Can't be player of color %d", q.quest->m13489val);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CQuest::MISSION_KEYMASTER:
|
|
||||||
return missionKeymaster();
|
|
||||||
|
|
||||||
} //end of switch
|
|
||||||
|
|
||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +94,7 @@ std::string CompleteQuest::questToString() const
|
|||||||
return "find " + VLC->generaltexth->tentColors[q.obj->subID] + " keymaster tent";
|
return "find " + VLC->generaltexth->tentColors[q.obj->subID] + " keymaster tent";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(q.quest->missionType == CQuest::MISSION_NONE)
|
if(q.quest->questName == CQuest::missionName(0))
|
||||||
return "inactive quest";
|
return "inactive quest";
|
||||||
|
|
||||||
MetaString ms;
|
MetaString ms;
|
||||||
@@ -137,7 +124,7 @@ TGoalVec CompleteQuest::missionArt() const
|
|||||||
|
|
||||||
CaptureObjectsBehavior findArts;
|
CaptureObjectsBehavior findArts;
|
||||||
|
|
||||||
for(auto art : q.quest->m5arts)
|
for(auto art : q.quest->mission.artifacts)
|
||||||
{
|
{
|
||||||
solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art)));
|
solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art)));
|
||||||
}
|
}
|
||||||
@@ -223,7 +210,7 @@ TGoalVec CompleteQuest::missionResources() const
|
|||||||
|
|
||||||
TGoalVec CompleteQuest::missionDestroyObj() const
|
TGoalVec CompleteQuest::missionDestroyObj() const
|
||||||
{
|
{
|
||||||
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||||
|
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return CaptureObjectsBehavior(q.obj).decompose();
|
return CaptureObjectsBehavior(q.obj).decompose();
|
||||||
|
@@ -25,7 +25,7 @@ namespace AIPathfinding
|
|||||||
return dynamic_cast<const IQuestObject *>(questInfo.obj)->checkQuest(node->actor->hero);
|
return dynamic_cast<const IQuestObject *>(questInfo.obj)->checkQuest(node->actor->hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
return questInfo.quest->progress == CQuest::NOT_ACTIVE
|
return questInfo.quest->activeForPlayers.count(node->actor->hero->getOwner())
|
||||||
|| questInfo.quest->checkQuest(node->actor->hero);
|
|| questInfo.quest->checkQuest(node->actor->hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -130,7 +130,9 @@ namespace AIPathfinding
|
|||||||
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
|
auto questInfo = QuestInfo(questObj->quest, destination.nodeObject, destination.coord);
|
||||||
QuestAction questAction(questInfo);
|
QuestAction questAction(questInfo);
|
||||||
|
|
||||||
if(destination.nodeObject->ID == Obj::QUEST_GUARD && questObj->quest->missionType == CQuest::MISSION_NONE)
|
if(destination.nodeObject->ID == Obj::QUEST_GUARD
|
||||||
|
&& questObj->quest->mission == Rewardable::Limiter{}
|
||||||
|
&& questObj->quest->killTarget == ObjectInstanceID::NONE)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -21,48 +21,43 @@ bool CompleteQuest::operator==(const CompleteQuest & other) const
|
|||||||
return q.quest->qid == other.q.quest->qid;
|
return q.quest->qid == other.q.quest->qid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isKeyMaster(const QuestInfo & q)
|
||||||
|
{
|
||||||
|
return q.obj && (q.obj->ID == Obj::BORDER_GATE || q.obj->ID == Obj::BORDERGUARD);
|
||||||
|
}
|
||||||
|
|
||||||
TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
||||||
{
|
{
|
||||||
TGoalVec solutions;
|
TGoalVec solutions;
|
||||||
|
|
||||||
if(q.quest->missionType && q.quest->progress != CQuest::COMPLETE)
|
if(!q.quest->isCompleted)
|
||||||
{
|
{
|
||||||
logAi->debug("Trying to realize quest: %s", questToString());
|
logAi->debug("Trying to realize quest: %s", questToString());
|
||||||
|
|
||||||
switch(q.quest->missionType)
|
if(isKeyMaster(q))
|
||||||
{
|
|
||||||
case CQuest::MISSION_ART:
|
|
||||||
return missionArt();
|
|
||||||
|
|
||||||
case CQuest::MISSION_HERO:
|
|
||||||
return missionHero();
|
|
||||||
|
|
||||||
case CQuest::MISSION_ARMY:
|
|
||||||
return missionArmy();
|
|
||||||
|
|
||||||
case CQuest::MISSION_RESOURCES:
|
|
||||||
return missionResources();
|
|
||||||
|
|
||||||
case CQuest::MISSION_KILL_HERO:
|
|
||||||
case CQuest::MISSION_KILL_CREATURE:
|
|
||||||
return missionDestroyObj();
|
|
||||||
|
|
||||||
case CQuest::MISSION_PRIMARY_STAT:
|
|
||||||
return missionIncreasePrimaryStat();
|
|
||||||
|
|
||||||
case CQuest::MISSION_LEVEL:
|
|
||||||
return missionLevel();
|
|
||||||
|
|
||||||
case CQuest::MISSION_PLAYER:
|
|
||||||
if(ai->playerID.getNum() != q.quest->m13489val)
|
|
||||||
logAi->debug("Can't be player of color %d", q.quest->m13489val);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CQuest::MISSION_KEYMASTER:
|
|
||||||
return missionKeymaster();
|
return missionKeymaster();
|
||||||
|
|
||||||
} //end of switch
|
if(!q.quest->mission.artifacts.empty())
|
||||||
|
return missionArt();
|
||||||
|
|
||||||
|
if(!q.quest->mission.heroes.empty())
|
||||||
|
return missionHero();
|
||||||
|
|
||||||
|
if(!q.quest->mission.creatures.empty())
|
||||||
|
return missionArmy();
|
||||||
|
|
||||||
|
if(q.quest->mission.resources.nonZero())
|
||||||
|
return missionResources();
|
||||||
|
|
||||||
|
if(q.quest->killTarget != ObjectInstanceID::NONE)
|
||||||
|
return missionDestroyObj();
|
||||||
|
|
||||||
|
for(auto & s : q.quest->mission.primary)
|
||||||
|
if(s)
|
||||||
|
return missionIncreasePrimaryStat();
|
||||||
|
|
||||||
|
if(q.quest->mission.heroLevel > 0)
|
||||||
|
return missionLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
return TGoalVec();
|
return TGoalVec();
|
||||||
@@ -70,7 +65,7 @@ TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
|||||||
|
|
||||||
TSubgoal CompleteQuest::whatToDoToAchieve()
|
TSubgoal CompleteQuest::whatToDoToAchieve()
|
||||||
{
|
{
|
||||||
if(q.quest->missionType == CQuest::MISSION_NONE)
|
if(q.quest->mission == Rewardable::Limiter{})
|
||||||
{
|
{
|
||||||
throw cannotFulfillGoalException("Can not complete inactive quest");
|
throw cannotFulfillGoalException("Can not complete inactive quest");
|
||||||
}
|
}
|
||||||
@@ -104,7 +99,7 @@ std::string CompleteQuest::completeMessage() const
|
|||||||
|
|
||||||
std::string CompleteQuest::questToString() const
|
std::string CompleteQuest::questToString() const
|
||||||
{
|
{
|
||||||
if(q.quest->missionType == CQuest::MISSION_NONE)
|
if(q.quest->questName == CQuest::missionName(0))
|
||||||
return "inactive quest";
|
return "inactive quest";
|
||||||
|
|
||||||
MetaString ms;
|
MetaString ms;
|
||||||
@@ -137,7 +132,7 @@ TGoalVec CompleteQuest::missionArt() const
|
|||||||
if(!solutions.empty())
|
if(!solutions.empty())
|
||||||
return solutions;
|
return solutions;
|
||||||
|
|
||||||
for(auto art : q.quest->m5arts)
|
for(auto art : q.quest->mission.artifacts)
|
||||||
{
|
{
|
||||||
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
||||||
}
|
}
|
||||||
@@ -165,7 +160,7 @@ TGoalVec CompleteQuest::missionArmy() const
|
|||||||
if(!solutions.empty())
|
if(!solutions.empty())
|
||||||
return solutions;
|
return solutions;
|
||||||
|
|
||||||
for(auto creature : q.quest->m6creatures)
|
for(auto creature : q.quest->mission.creatures)
|
||||||
{
|
{
|
||||||
solutions.push_back(sptr(GatherTroops(creature.type->getId(), creature.count)));
|
solutions.push_back(sptr(GatherTroops(creature.type->getId(), creature.count)));
|
||||||
}
|
}
|
||||||
@@ -179,7 +174,7 @@ TGoalVec CompleteQuest::missionIncreasePrimaryStat() const
|
|||||||
|
|
||||||
if(solutions.empty())
|
if(solutions.empty())
|
||||||
{
|
{
|
||||||
for(int i = 0; i < q.quest->m2stats.size(); ++i)
|
for(int i = 0; i < q.quest->mission.primary.size(); ++i)
|
||||||
{
|
{
|
||||||
// TODO: library, school and other boost objects
|
// TODO: library, school and other boost objects
|
||||||
logAi->debug("Don't know how to increase primary stat %d", i);
|
logAi->debug("Don't know how to increase primary stat %d", i);
|
||||||
@@ -195,7 +190,7 @@ TGoalVec CompleteQuest::missionLevel() const
|
|||||||
|
|
||||||
if(solutions.empty())
|
if(solutions.empty())
|
||||||
{
|
{
|
||||||
logAi->debug("Don't know how to reach hero level %d", q.quest->m13489val);
|
logAi->debug("Don't know how to reach hero level %d", q.quest->mission.heroLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return solutions;
|
return solutions;
|
||||||
@@ -227,10 +222,10 @@ TGoalVec CompleteQuest::missionResources() const
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(int i = 0; i < q.quest->m7resources.size(); ++i)
|
for(int i = 0; i < q.quest->mission.resources.size(); ++i)
|
||||||
{
|
{
|
||||||
if(q.quest->m7resources[i])
|
if(q.quest->mission.resources[i])
|
||||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
|
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->mission.resources[i])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +241,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
|||||||
{
|
{
|
||||||
TGoalVec solutions;
|
TGoalVec solutions;
|
||||||
|
|
||||||
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||||
|
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return ai->ah->howToVisitObj(q.obj);
|
return ai->ah->howToVisitObj(q.obj);
|
||||||
|
@@ -148,11 +148,11 @@ void CQuestLog::recreateLabelList()
|
|||||||
int currentLabel = 0;
|
int currentLabel = 0;
|
||||||
for (int i = 0; i < quests.size(); ++i)
|
for (int i = 0; i < quests.size(); ++i)
|
||||||
{
|
{
|
||||||
// Quests with MISSION_NONE type don't have text for them and can't be displayed
|
// Quests without mision don't have text for them and can't be displayed
|
||||||
if (quests[i].quest->missionType == CQuest::MISSION_NONE)
|
if (quests[i].quest->mission == Rewardable::Limiter{})
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (quests[i].quest->progress == CQuest::COMPLETE)
|
if (quests[i].quest->isCompleted)
|
||||||
{
|
{
|
||||||
completeMissing = false;
|
completeMissing = false;
|
||||||
if (hideComplete)
|
if (hideComplete)
|
||||||
@@ -180,7 +180,7 @@ void CQuestLog::recreateLabelList()
|
|||||||
labels.push_back(label);
|
labels.push_back(label);
|
||||||
|
|
||||||
// Select latest active quest
|
// Select latest active quest
|
||||||
if (quests[i].quest->progress != CQuest::COMPLETE)
|
if(!quests[i].quest->isCompleted)
|
||||||
selectQuest(i, currentLabel);
|
selectQuest(i, currentLabel);
|
||||||
|
|
||||||
currentLabel = static_cast<int>(labels.size());
|
currentLabel = static_cast<int>(labels.size());
|
||||||
@@ -236,7 +236,7 @@ void CQuestLog::selectQuest(int which, int labelId)
|
|||||||
|
|
||||||
MetaString text;
|
MetaString text;
|
||||||
std::vector<Component> components;
|
std::vector<Component> components;
|
||||||
currentQuest->quest->getVisitText (text, components, currentQuest->quest->isCustomFirst, true);
|
currentQuest->quest->getVisitText(text, components, true);
|
||||||
if(description->slider)
|
if(description->slider)
|
||||||
description->slider->scrollToMin(); // scroll text to start position
|
description->slider->scrollToMin(); // scroll text to start position
|
||||||
description->setText(text.toString()); //TODO: use special log entry text
|
description->setText(text.toString()); //TODO: use special log entry text
|
||||||
@@ -247,9 +247,15 @@ void CQuestLog::selectQuest(int which, int labelId)
|
|||||||
int descriptionHeight = DESCRIPTION_HEIGHT_MAX;
|
int descriptionHeight = DESCRIPTION_HEIGHT_MAX;
|
||||||
if(componentsSize)
|
if(componentsSize)
|
||||||
{
|
{
|
||||||
descriptionHeight -= 15;
|
|
||||||
CComponent::ESize imageSize = CComponent::large;
|
CComponent::ESize imageSize = CComponent::large;
|
||||||
switch (currentQuest->quest->missionType)
|
if (componentsSize > 4)
|
||||||
|
{
|
||||||
|
imageSize = CComponent::small; // Only small icons can be used for resources as 4+ icons take too much space
|
||||||
|
descriptionHeight -= 155;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
descriptionHeight -= 130;
|
||||||
|
/*switch (currentQuest->quest->missionType)
|
||||||
{
|
{
|
||||||
case CQuest::MISSION_ARMY:
|
case CQuest::MISSION_ARMY:
|
||||||
{
|
{
|
||||||
@@ -285,7 +291,7 @@ void CQuestLog::selectQuest(int which, int labelId)
|
|||||||
default:
|
default:
|
||||||
descriptionHeight -= 115;
|
descriptionHeight -= 115;
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
|
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ Rewardable object is defined similarly to other objects, with key difference bei
|
|||||||
// additional list of conditions. Limiter will be valid if any of these conditions are true
|
// additional list of conditions. Limiter will be valid if any of these conditions are true
|
||||||
"anyOf" : [
|
"anyOf" : [
|
||||||
{
|
{
|
||||||
// See "Configurable Properties" section for additiona parameters
|
// See "Configurable Properties" section for additional parameters
|
||||||
<additional properties>
|
<additional properties>
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -80,12 +80,12 @@ Rewardable object is defined similarly to other objects, with key difference bei
|
|||||||
// additional list of conditions. Limiter will be valid only if none of these conditions are true
|
// additional list of conditions. Limiter will be valid only if none of these conditions are true
|
||||||
"noneOf" : [
|
"noneOf" : [
|
||||||
{
|
{
|
||||||
// See "Configurable Properties" section for additiona parameters
|
// See "Configurable Properties" section for additional parameters
|
||||||
<additional properties>
|
<additional properties>
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// See "Configurable Properties" section for additiona parameters
|
// See "Configurable Properties" section for additional parameters
|
||||||
<additional properties>
|
<additional properties>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ Rewardable object is defined similarly to other objects, with key difference bei
|
|||||||
// object will be disappeared after taking reward is set to true
|
// object will be disappeared after taking reward is set to true
|
||||||
"removeObject": false
|
"removeObject": false
|
||||||
|
|
||||||
// See "Configurable Properties" section for additiona parameters
|
// See "Configurable Properties" section for additional parameters
|
||||||
<additional properties>
|
<additional properties>
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -451,3 +451,30 @@ Keep in mind, that all randomization is performed on map load and on object rese
|
|||||||
"schoolLevel": 3
|
"schoolLevel": 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Player color
|
||||||
|
- Can be used as limiter
|
||||||
|
- Can NOT be used as reward
|
||||||
|
- Only players with specific color can pass the limiter
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"colors" : [ "red", "blue", "tan", "green", "orange", "purple", "teal", "pink" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hero types
|
||||||
|
- Can be used as limiter
|
||||||
|
- Can NOT be used as reward
|
||||||
|
- Only specific heroes can pass the limiter
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"heroes" : [ "orrin" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hero classes
|
||||||
|
- Can be used as limiter
|
||||||
|
- Can NOT be used as reward
|
||||||
|
- Only heroes belonging to specific classes can pass the limiter
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"heroClasses" : [ "battlemage" ]
|
||||||
|
```
|
@@ -1029,6 +1029,14 @@ void CStackBasicDescriptor::setType(const CCreature * c)
|
|||||||
type = c;
|
type = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator== (const CStackBasicDescriptor & l, const CStackBasicDescriptor & r)
|
||||||
|
{
|
||||||
|
return (!l.type && !r.type)
|
||||||
|
|| (l.type && r.type
|
||||||
|
&& l.type->getId() == r.type->getId()
|
||||||
|
&& l.count == r.count);
|
||||||
|
}
|
||||||
|
|
||||||
void CStackBasicDescriptor::serializeJson(JsonSerializeFormat & handler)
|
void CStackBasicDescriptor::serializeJson(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
handler.serializeInt("amount", count);
|
handler.serializeInt("amount", count);
|
||||||
|
@@ -43,6 +43,8 @@ public:
|
|||||||
|
|
||||||
virtual void setType(const CCreature * c);
|
virtual void setType(const CCreature * c);
|
||||||
|
|
||||||
|
friend bool operator== (const CStackBasicDescriptor & l, const CStackBasicDescriptor & r);
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
if(h.saving)
|
if(h.saving)
|
||||||
|
@@ -662,9 +662,9 @@ std::string CGameInfoCallback::getTavernRumor(const CGObjectInstance * townOrTav
|
|||||||
case RumorState::TYPE_SPECIAL:
|
case RumorState::TYPE_SPECIAL:
|
||||||
text.replaceLocalString(EMetaText::GENERAL_TXT, rumor.first);
|
text.replaceLocalString(EMetaText::GENERAL_TXT, rumor.first);
|
||||||
if(rumor.first == RumorState::RUMOR_GRAIL)
|
if(rumor.first == RumorState::RUMOR_GRAIL)
|
||||||
text.replaceTextID(TextIdentifier("core", "genrltxt", "arraytxt", 158 + rumor.second).get());
|
text.replaceTextID(TextIdentifier("core", "arraytxt", 158 + rumor.second).get());
|
||||||
else
|
else
|
||||||
text.replaceTextID(TextIdentifier("core", "genrltxt", "capitalColors", rumor.second).get());
|
text.replaceTextID(TextIdentifier("core", "plcolors", rumor.second).get());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case RumorState::TYPE_MAP:
|
case RumorState::TYPE_MAP:
|
||||||
@@ -672,7 +672,7 @@ std::string CGameInfoCallback::getTavernRumor(const CGObjectInstance * townOrTav
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RumorState::TYPE_RAND:
|
case RumorState::TYPE_RAND:
|
||||||
text.replaceTextID(TextIdentifier("core", "genrltxt", "randtvrn", rumor.first).get());
|
text.replaceTextID(TextIdentifier("core", "randtvrn", rumor.first).get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -264,21 +264,21 @@ void TextLocalizationContainer::registerStringOverride(const std::string & modCo
|
|||||||
|
|
||||||
void TextLocalizationContainer::addSubContainer(const TextLocalizationContainer & container)
|
void TextLocalizationContainer::addSubContainer(const TextLocalizationContainer & container)
|
||||||
{
|
{
|
||||||
subContainers.insert(&container);
|
subContainers.push_back(&container);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextLocalizationContainer::removeSubContainer(const TextLocalizationContainer & container)
|
void TextLocalizationContainer::removeSubContainer(const TextLocalizationContainer & container)
|
||||||
{
|
{
|
||||||
subContainers.erase(&container);
|
subContainers.erase(std::remove(subContainers.begin(), subContainers.end(), &container), subContainers.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string & TextLocalizationContainer::deserialize(const TextIdentifier & identifier) const
|
const std::string & TextLocalizationContainer::deserialize(const TextIdentifier & identifier) const
|
||||||
{
|
{
|
||||||
if(stringsLocalizations.count(identifier.get()) == 0)
|
if(stringsLocalizations.count(identifier.get()) == 0)
|
||||||
{
|
{
|
||||||
for(const auto * container : subContainers)
|
for(auto containerIter = subContainers.rbegin(); containerIter != subContainers.rend(); ++containerIter)
|
||||||
if(container->identifierExists(identifier))
|
if((*containerIter)->identifierExists(identifier))
|
||||||
return container->deserialize(identifier);
|
return (*containerIter)->deserialize(identifier);
|
||||||
|
|
||||||
logGlobal->error("Unable to find localization for string '%s'", identifier.get());
|
logGlobal->error("Unable to find localization for string '%s'", identifier.get());
|
||||||
return identifier.get();
|
return identifier.get();
|
||||||
@@ -547,7 +547,7 @@ CGeneralTextHandler::CGeneralTextHandler():
|
|||||||
|
|
||||||
for (size_t i = 0; i < 9; ++i) //9 types of quests
|
for (size_t i = 0; i < 9; ++i) //9 types of quests
|
||||||
{
|
{
|
||||||
std::string questName = CQuest::missionName(static_cast<CQuest::Emission>(1+i));
|
std::string questName = CQuest::missionName(1+i);
|
||||||
|
|
||||||
for (size_t j = 0; j < 5; ++j)
|
for (size_t j = 0; j < 5; ++j)
|
||||||
{
|
{
|
||||||
|
@@ -146,7 +146,7 @@ protected:
|
|||||||
/// map identifier -> localization
|
/// map identifier -> localization
|
||||||
std::unordered_map<std::string, StringState> stringsLocalizations;
|
std::unordered_map<std::string, StringState> stringsLocalizations;
|
||||||
|
|
||||||
std::set<const TextLocalizationContainer *> subContainers;
|
std::vector<const TextLocalizationContainer *> subContainers;
|
||||||
|
|
||||||
/// add selected string to internal storage as high-priority strings
|
/// add selected string to internal storage as high-priority strings
|
||||||
void registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized);
|
void registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized);
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
#include "CCreatureSet.h"
|
#include "CCreatureSet.h"
|
||||||
#include "spells/CSpellHandler.h"
|
#include "spells/CSpellHandler.h"
|
||||||
#include "CSkillHandler.h"
|
#include "CSkillHandler.h"
|
||||||
|
#include "CHeroHandler.h"
|
||||||
#include "IGameCallback.h"
|
#include "IGameCallback.h"
|
||||||
#include "mapObjects/IObjectInterface.h"
|
#include "mapObjects/IObjectInterface.h"
|
||||||
#include "modding/IdentifierStorage.h"
|
#include "modding/IdentifierStorage.h"
|
||||||
@@ -282,6 +283,46 @@ namespace JsonRandom
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng)
|
||||||
|
{
|
||||||
|
std::vector<PlayerColor> ret;
|
||||||
|
std::set<std::string> def;
|
||||||
|
|
||||||
|
for(auto & color : GameConstants::PLAYER_COLOR_NAMES)
|
||||||
|
def.insert(color);
|
||||||
|
|
||||||
|
for(auto & entry : value.Vector())
|
||||||
|
{
|
||||||
|
auto key = loadKey(entry, rng, def);
|
||||||
|
auto pos = vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, key);
|
||||||
|
if(pos < 0)
|
||||||
|
logMod->warn("Unable to determine player color %s", key);
|
||||||
|
else
|
||||||
|
ret.emplace_back(pos);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng)
|
||||||
|
{
|
||||||
|
std::vector<HeroTypeID> ret;
|
||||||
|
for(auto & entry : value.Vector())
|
||||||
|
{
|
||||||
|
ret.push_back(VLC->heroTypes()->getByIndex(VLC->identifiers()->getIdentifier("hero", entry.String()).value())->getId());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng)
|
||||||
|
{
|
||||||
|
std::vector<HeroClassID> ret;
|
||||||
|
for(auto & entry : value.Vector())
|
||||||
|
{
|
||||||
|
ret.push_back(VLC->heroClasses()->getByIndex(VLC->identifiers()->getIdentifier("heroClass", entry.String()).value())->getId());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng)
|
CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng)
|
||||||
{
|
{
|
||||||
CStackBasicDescriptor stack;
|
CStackBasicDescriptor stack;
|
||||||
|
@@ -48,6 +48,10 @@ namespace JsonRandom
|
|||||||
DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);
|
DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);
|
||||||
DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value);
|
DLL_LINKAGE std::vector<RandomStackInfo> evaluateCreatures(const JsonNode & value);
|
||||||
|
|
||||||
|
DLL_LINKAGE std::vector<PlayerColor> loadColors(const JsonNode & value, CRandomGenerator & rng);
|
||||||
|
DLL_LINKAGE std::vector<HeroTypeID> loadHeroes(const JsonNode & value, CRandomGenerator & rng);
|
||||||
|
DLL_LINKAGE std::vector<HeroClassID> loadHeroClasses(const JsonNode & value, CRandomGenerator & rng);
|
||||||
|
|
||||||
DLL_LINKAGE std::vector<Bonus> loadBonuses(const JsonNode & value);
|
DLL_LINKAGE std::vector<Bonus> loadBonuses(const JsonNode & value);
|
||||||
//DLL_LINKAGE std::vector<Component> loadComponents(const JsonNode & value);
|
//DLL_LINKAGE std::vector<Component> loadComponents(const JsonNode & value);
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
#include <vcmi/FactionService.h>
|
#include <vcmi/FactionService.h>
|
||||||
#include <vcmi/HeroType.h>
|
#include <vcmi/HeroType.h>
|
||||||
#include <vcmi/HeroTypeService.h>
|
#include <vcmi/HeroTypeService.h>
|
||||||
|
#include <vcmi/HeroClass.h>
|
||||||
|
#include <vcmi/HeroClassService.h>
|
||||||
|
|
||||||
#include <vcmi/spells/Spell.h>
|
#include <vcmi/spells/Spell.h>
|
||||||
#include <vcmi/spells/Service.h>
|
#include <vcmi/spells/Service.h>
|
||||||
@@ -103,6 +105,25 @@ namespace GameConstants
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
si32 HeroClassID::decode(const std::string & identifier)
|
||||||
|
{
|
||||||
|
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "heroClass", identifier);
|
||||||
|
if(rawId)
|
||||||
|
return rawId.value();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HeroClassID::encode(const si32 index)
|
||||||
|
{
|
||||||
|
return VLC->heroClasses()->getByIndex(index)->getJsonKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HeroClassID::entityType()
|
||||||
|
{
|
||||||
|
return "heroClass";
|
||||||
|
}
|
||||||
|
|
||||||
si32 HeroTypeID::decode(const std::string & identifier)
|
si32 HeroTypeID::decode(const std::string & identifier)
|
||||||
{
|
{
|
||||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "hero", identifier);
|
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "hero", identifier);
|
||||||
|
@@ -223,6 +223,10 @@ class HeroClassID : public Identifier<HeroClassID>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Identifier<HeroClassID>::Identifier;
|
using Identifier<HeroClassID>::Identifier;
|
||||||
|
///json serialization helpers
|
||||||
|
DLL_LINKAGE static si32 decode(const std::string & identifier);
|
||||||
|
DLL_LINKAGE static std::string encode(const si32 index);
|
||||||
|
static std::string entityType();
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeroTypeID : public Identifier<HeroTypeID>
|
class HeroTypeID : public Identifier<HeroTypeID>
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "../mapping/CMap.h"
|
#include "../mapping/CMap.h"
|
||||||
#include "../modding/ModScope.h"
|
#include "../modding/ModScope.h"
|
||||||
#include "../modding/ModUtility.h"
|
#include "../modding/ModUtility.h"
|
||||||
|
#include "../spells/CSpellHandler.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@@ -37,16 +38,17 @@ std::map <PlayerColor, std::set <ui8> > CGKeys::playerKeyMap;
|
|||||||
//TODO: Remove constructor
|
//TODO: Remove constructor
|
||||||
CQuest::CQuest():
|
CQuest::CQuest():
|
||||||
qid(-1),
|
qid(-1),
|
||||||
missionType(MISSION_NONE),
|
isCompleted(false),
|
||||||
progress(NOT_ACTIVE),
|
|
||||||
lastDay(-1),
|
lastDay(-1),
|
||||||
m13489val(0),
|
killTarget(ObjectInstanceID::NONE),
|
||||||
textOption(0),
|
textOption(0),
|
||||||
completedOption(0),
|
completedOption(0),
|
||||||
stackDirection(0),
|
stackDirection(0),
|
||||||
isCustomFirst(false),
|
isCustomFirst(false),
|
||||||
isCustomNext(false),
|
isCustomNext(false),
|
||||||
isCustomComplete(false)
|
isCustomComplete(false),
|
||||||
|
repeatedQuest(false),
|
||||||
|
questName(CQuest::missionName(0))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,9 +58,9 @@ static std::string visitedTxt(const bool visited)
|
|||||||
return VLC->generaltexth->allTexts[id];
|
return VLC->generaltexth->allTexts[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string & CQuest::missionName(CQuest::Emission mission)
|
const std::string & CQuest::missionName(int mission)
|
||||||
{
|
{
|
||||||
static const std::array<std::string, 11> names = {
|
static const std::array<std::string, 13> names = {
|
||||||
"empty",
|
"empty",
|
||||||
"heroLevel",
|
"heroLevel",
|
||||||
"primarySkill",
|
"primarySkill",
|
||||||
@@ -69,7 +71,9 @@ const std::string & CQuest::missionName(CQuest::Emission mission)
|
|||||||
"bringResources",
|
"bringResources",
|
||||||
"bringHero",
|
"bringHero",
|
||||||
"bringPlayer",
|
"bringPlayer",
|
||||||
"keymaster"
|
"keymaster",
|
||||||
|
"hota",
|
||||||
|
"other"
|
||||||
};
|
};
|
||||||
|
|
||||||
if(static_cast<size_t>(mission) < names.size())
|
if(static_cast<size_t>(mission) < names.size())
|
||||||
@@ -99,7 +103,7 @@ bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
|
|||||||
ui32 count = 0;
|
ui32 count = 0;
|
||||||
ui32 slotsCount = 0;
|
ui32 slotsCount = 0;
|
||||||
bool hasExtraCreatures = false;
|
bool hasExtraCreatures = false;
|
||||||
for(cre = q->m6creatures.begin(); cre != q->m6creatures.end(); ++cre)
|
for(cre = q->mission.creatures.begin(); cre != q->mission.creatures.end(); ++cre)
|
||||||
{
|
{
|
||||||
for(count = 0, it = army->Slots().begin(); it != army->Slots().end(); ++it)
|
for(count = 0, it = army->Slots().begin(); it != army->Slots().end(); ++it)
|
||||||
{
|
{
|
||||||
@@ -121,348 +125,212 @@ bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
|
|||||||
|
|
||||||
bool CQuest::checkQuest(const CGHeroInstance * h) const
|
bool CQuest::checkQuest(const CGHeroInstance * h) const
|
||||||
{
|
{
|
||||||
switch (missionType)
|
if(!mission.heroAllowed(h))
|
||||||
{
|
return false;
|
||||||
case MISSION_NONE:
|
|
||||||
return true;
|
|
||||||
case MISSION_LEVEL:
|
|
||||||
return m13489val <= h->level;
|
|
||||||
case MISSION_PRIMARY_STAT:
|
|
||||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
|
||||||
{
|
|
||||||
if(h->getPrimSkillLevel(static_cast<PrimarySkill>(i)) < static_cast<int>(m2stats[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case MISSION_KILL_HERO:
|
|
||||||
case MISSION_KILL_CREATURE:
|
|
||||||
if(!CGHeroInstance::cb->getObjByQuestIdentifier(m13489val))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
case MISSION_ART:
|
|
||||||
{
|
|
||||||
// if the object was deserialized
|
|
||||||
if(artifactsRequirements.empty())
|
|
||||||
for(const auto & id : m5arts)
|
|
||||||
++artifactsRequirements[id];
|
|
||||||
|
|
||||||
size_t reqSlots = 0;
|
if(killTarget != ObjectInstanceID::NONE)
|
||||||
for(const auto & elem : artifactsRequirements)
|
{
|
||||||
{
|
if(CGHeroInstance::cb->getObjByQuestIdentifier(killTarget))
|
||||||
// check required amount of artifacts
|
|
||||||
if(h->getArtPosCount(elem.first, false, true, true) < elem.second)
|
|
||||||
return false;
|
|
||||||
if(!h->hasArt(elem.first))
|
|
||||||
reqSlots += h->getAssemblyByConstituent(elem.first)->getPartsInfo().size() - 2;
|
|
||||||
}
|
|
||||||
if(ArtifactUtils::isBackpackFreeSlots(h, reqSlots))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case MISSION_ARMY:
|
|
||||||
return checkMissionArmy(this, h);
|
|
||||||
case MISSION_RESOURCES:
|
|
||||||
for(GameResID i = EGameResID::WOOD; i <= EGameResID::GOLD; ++i) //including Mithril ?
|
|
||||||
{ //Quest has no direct access to callback
|
|
||||||
if(CGHeroInstance::cb->getResource(h->tempOwner, i) < static_cast<int>(m7resources[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case MISSION_HERO:
|
|
||||||
return m13489val == h->type->getIndex();
|
|
||||||
case MISSION_PLAYER:
|
|
||||||
return m13489val == h->getOwner().getNum();
|
|
||||||
default:
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components, bool isCustom, bool firstVisit, const CGHeroInstance * h) const
|
void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
|
||||||
|
{
|
||||||
|
for(auto & elem : mission.artifacts)
|
||||||
|
{
|
||||||
|
if(h->hasArt(elem))
|
||||||
|
{
|
||||||
|
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto * assembly = h->getAssemblyByConstituent(elem);
|
||||||
|
assert(assembly);
|
||||||
|
auto parts = assembly->getPartsInfo();
|
||||||
|
|
||||||
|
// Remove the assembly
|
||||||
|
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(assembly)));
|
||||||
|
|
||||||
|
// Disassemble this backpack artifact
|
||||||
|
for(const auto & ci : parts)
|
||||||
|
{
|
||||||
|
if(ci.art->getTypeId() != elem)
|
||||||
|
cb->giveHeroNewArtifact(h, ci.art->artType, ArtifactPosition::BACKPACK_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb->takeCreatures(h->id, mission.creatures);
|
||||||
|
cb->giveResources(h->getOwner(), mission.resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CQuest::addTextReplacements(MetaString & text, std::vector<Component> & components) const
|
||||||
|
{
|
||||||
|
if(mission.heroLevel > 0)
|
||||||
|
text.replaceNumber(mission.heroLevel);
|
||||||
|
|
||||||
|
if(mission.heroExperience > 0)
|
||||||
|
text.replaceNumber(mission.heroExperience);
|
||||||
|
|
||||||
|
{ //primary skills
|
||||||
|
MetaString loot;
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if(mission.primary[i])
|
||||||
|
{
|
||||||
|
loot.appendRawString("%d %s");
|
||||||
|
loot.replaceNumber(mission.primary[i]);
|
||||||
|
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto & skill : mission.secondary)
|
||||||
|
{
|
||||||
|
loot.appendTextID(VLC->skillh->getById(skill.first)->getNameTextID());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto & spell : mission.spells)
|
||||||
|
{
|
||||||
|
loot.appendTextID(VLC->spellh->getById(spell)->getNameTextID());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!loot.empty())
|
||||||
|
text.replaceRawString(loot.buildList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(killTarget != ObjectInstanceID::NONE && !heroName.empty())
|
||||||
|
{
|
||||||
|
components.emplace_back(Component::EComponentType::HERO_PORTRAIT, heroPortrait, 0, 0);
|
||||||
|
addKillTargetReplacements(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(killTarget != ObjectInstanceID::NONE && stackToKill.type)
|
||||||
|
{
|
||||||
|
components.emplace_back(stackToKill);
|
||||||
|
addKillTargetReplacements(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mission.heroes.empty())
|
||||||
|
text.replaceRawString(VLC->heroh->getById(mission.heroes.front())->getNameTranslated());
|
||||||
|
|
||||||
|
if(!mission.artifacts.empty())
|
||||||
|
{
|
||||||
|
MetaString loot;
|
||||||
|
for(const auto & elem : mission.artifacts)
|
||||||
|
{
|
||||||
|
loot.appendRawString("%s");
|
||||||
|
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
||||||
|
}
|
||||||
|
text.replaceRawString(loot.buildList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mission.creatures.empty())
|
||||||
|
{
|
||||||
|
MetaString loot;
|
||||||
|
for(const auto & elem : mission.creatures)
|
||||||
|
{
|
||||||
|
loot.appendRawString("%s");
|
||||||
|
loot.replaceCreatureName(elem);
|
||||||
|
}
|
||||||
|
text.replaceRawString(loot.buildList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mission.resources.nonZero())
|
||||||
|
{
|
||||||
|
MetaString loot;
|
||||||
|
for(int i = 0; i < 7; ++i)
|
||||||
|
{
|
||||||
|
if(mission.resources[i])
|
||||||
|
{
|
||||||
|
loot.appendRawString("%d %s");
|
||||||
|
loot.replaceNumber(mission.resources[i]);
|
||||||
|
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text.replaceRawString(loot.buildList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mission.players.empty())
|
||||||
|
{
|
||||||
|
MetaString loot;
|
||||||
|
for(auto & p : mission.players)
|
||||||
|
loot.appendLocalString(EMetaText::COLOR, p);
|
||||||
|
|
||||||
|
text.replaceRawString(loot.buildList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lastDay >= 0)
|
||||||
|
text.replaceNumber(lastDay - IObjectInterface::cb->getDate(Date::DAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components, bool firstVisit, const CGHeroInstance * h) const
|
||||||
{
|
{
|
||||||
MetaString text;
|
|
||||||
bool failRequirements = (h ? !checkQuest(h) : true);
|
bool failRequirements = (h ? !checkQuest(h) : true);
|
||||||
|
mission.loadComponents(components, h);
|
||||||
|
|
||||||
if(firstVisit)
|
if(firstVisit)
|
||||||
{
|
iwText.appendRawString(firstVisitText.toString());
|
||||||
isCustom = isCustomFirst;
|
|
||||||
text = firstVisitText;
|
|
||||||
iwText.appendRawString(text.toString());
|
|
||||||
}
|
|
||||||
else if(failRequirements)
|
else if(failRequirements)
|
||||||
{
|
iwText.appendRawString(nextVisitText.toString());
|
||||||
isCustom = isCustomNext;
|
|
||||||
text = nextVisitText;
|
if(lastDay >= 0)
|
||||||
iwText.appendRawString(text.toString());
|
iwText.appendTextID(TextIdentifier("core", "seerhut", "time", textOption).get());
|
||||||
}
|
|
||||||
switch (missionType)
|
addTextReplacements(iwText, components);
|
||||||
{
|
|
||||||
case MISSION_LEVEL:
|
|
||||||
components.emplace_back(Component::EComponentType::EXPERIENCE, 0, m13489val, 0);
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceNumber(m13489val);
|
|
||||||
break;
|
|
||||||
case MISSION_PRIMARY_STAT:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(int i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
if(m2stats[i])
|
|
||||||
{
|
|
||||||
components.emplace_back(Component::EComponentType::PRIM_SKILL, i, m2stats[i], 0);
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m2stats[i]);
|
|
||||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isCustom)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_HERO:
|
|
||||||
components.emplace_back(Component::EComponentType::HERO_PORTRAIT, heroPortrait, 0, 0);
|
|
||||||
if(!isCustom)
|
|
||||||
addReplacements(iwText, text.toString());
|
|
||||||
break;
|
|
||||||
case MISSION_HERO:
|
|
||||||
//FIXME: portrait may not match hero, if custom portrait was set in map editor
|
|
||||||
components.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroh->objects[m13489val]->imageIndex, 0, 0);
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_CREATURE:
|
|
||||||
{
|
|
||||||
components.emplace_back(stackToKill);
|
|
||||||
if(!isCustom)
|
|
||||||
{
|
|
||||||
addReplacements(iwText, text.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_ART:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m5arts)
|
|
||||||
{
|
|
||||||
components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0);
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
|
||||||
}
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_ARMY:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m6creatures)
|
|
||||||
{
|
|
||||||
components.emplace_back(elem);
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceCreatureName(elem);
|
|
||||||
}
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_RESOURCES:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(int i = 0; i < 7; ++i)
|
|
||||||
{
|
|
||||||
if(m7resources[i])
|
|
||||||
{
|
|
||||||
components.emplace_back(Component::EComponentType::RESOURCE, i, m7resources[i], 0);
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m7resources[i]);
|
|
||||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_PLAYER:
|
|
||||||
components.emplace_back(Component::EComponentType::FLAG, m13489val, 0, 0);
|
|
||||||
if(!isCustom)
|
|
||||||
iwText.replaceLocalString(EMetaText::COLOR, m13489val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||||
{
|
{
|
||||||
// Quests with MISSION_NONE type don't have a text for them
|
|
||||||
assert(missionType != MISSION_NONE);
|
|
||||||
|
|
||||||
if(onHover)
|
if(onHover)
|
||||||
ms.appendRawString("\n\n");
|
ms.appendRawString("\n\n");
|
||||||
|
|
||||||
std::string questName = missionName(missionType);
|
|
||||||
std::string questState = missionState(onHover ? 3 : 4);
|
std::string questState = missionState(onHover ? 3 : 4);
|
||||||
|
|
||||||
ms.appendRawString(VLC->generaltexth->translate("core.seerhut.quest", questName, questState,textOption));
|
ms.appendTextID(TextIdentifier("core", "seerhut", "quest", questName, questState, textOption).get());
|
||||||
|
|
||||||
switch(missionType)
|
std::vector<Component> components;
|
||||||
{
|
addTextReplacements(ms, components);
|
||||||
case MISSION_LEVEL:
|
|
||||||
ms.replaceNumber(m13489val);
|
|
||||||
break;
|
|
||||||
case MISSION_PRIMARY_STAT:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
if (m2stats[i])
|
|
||||||
{
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m2stats[i]);
|
|
||||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ms.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_HERO:
|
|
||||||
ms.replaceRawString(heroName);
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_CREATURE:
|
|
||||||
ms.replaceCreatureName(stackToKill);
|
|
||||||
break;
|
|
||||||
case MISSION_ART:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m5arts)
|
|
||||||
{
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
|
||||||
}
|
|
||||||
ms.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_ARMY:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m6creatures)
|
|
||||||
{
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceCreatureName(elem);
|
|
||||||
}
|
|
||||||
ms.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_RESOURCES:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for (int i = 0; i < 7; ++i)
|
|
||||||
{
|
|
||||||
if (m7resources[i])
|
|
||||||
{
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m7resources[i]);
|
|
||||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ms.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_HERO:
|
|
||||||
ms.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
|
|
||||||
break;
|
|
||||||
case MISSION_PLAYER:
|
|
||||||
ms.replaceRawString(VLC->generaltexth->colors[m13489val]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::getCompletionText(MetaString &iwText) const
|
void CQuest::getCompletionText(MetaString &iwText) const
|
||||||
{
|
{
|
||||||
iwText.appendRawString(completedText.toString());
|
iwText.appendRawString(completedText.toString());
|
||||||
switch(missionType)
|
|
||||||
{
|
std::vector<Component> components;
|
||||||
case CQuest::MISSION_LEVEL:
|
addTextReplacements(iwText, components);
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceNumber(m13489val);
|
|
||||||
break;
|
|
||||||
case CQuest::MISSION_PRIMARY_STAT:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
assert(m2stats.size() <= 4);
|
|
||||||
for (int i = 0; i < m2stats.size(); ++i)
|
|
||||||
{
|
|
||||||
if (m2stats[i])
|
|
||||||
{
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m2stats[i]);
|
|
||||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CQuest::MISSION_ART:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m5arts)
|
|
||||||
{
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
|
||||||
}
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CQuest::MISSION_ARMY:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for(const auto & elem : m6creatures)
|
|
||||||
{
|
|
||||||
loot.appendRawString("%s");
|
|
||||||
loot.replaceCreatureName(elem);
|
|
||||||
}
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CQuest::MISSION_RESOURCES:
|
|
||||||
{
|
|
||||||
MetaString loot;
|
|
||||||
for (int i = 0; i < 7; ++i)
|
|
||||||
{
|
|
||||||
if (m7resources[i])
|
|
||||||
{
|
|
||||||
loot.appendRawString("%d %s");
|
|
||||||
loot.replaceNumber(m7resources[i]);
|
|
||||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(loot.buildList());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_HERO:
|
|
||||||
case MISSION_KILL_CREATURE:
|
|
||||||
if (!isCustomComplete)
|
|
||||||
addReplacements(iwText, completedText.toString());
|
|
||||||
break;
|
|
||||||
case MISSION_HERO:
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
|
|
||||||
break;
|
|
||||||
case MISSION_PLAYER:
|
|
||||||
if (!isCustomComplete)
|
|
||||||
iwText.replaceRawString(VLC->generaltexth->colors[m13489val]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::addArtifactID(const ArtifactID & id)
|
void CQuest::defineQuestName()
|
||||||
{
|
{
|
||||||
m5arts.push_back(id);
|
//standard quests
|
||||||
++artifactsRequirements[id];
|
questName = CQuest::missionName(0);
|
||||||
|
if(mission != Rewardable::Limiter{}) questName = CQuest::missionName(12);
|
||||||
|
if(mission.heroLevel > 0) questName = CQuest::missionName(1);
|
||||||
|
for(auto & s : mission.primary) if(s) questName = CQuest::missionName(2);
|
||||||
|
if(!mission.spells.empty()) questName = CQuest::missionName(2);
|
||||||
|
if(!mission.secondary.empty()) questName = CQuest::missionName(2);
|
||||||
|
if(killTarget != ObjectInstanceID::NONE && !heroName.empty()) questName = CQuest::missionName(3);
|
||||||
|
if(killTarget != ObjectInstanceID::NONE && stackToKill.getType()) questName = CQuest::missionName(4);
|
||||||
|
if(!mission.artifacts.empty()) questName = CQuest::missionName(5);
|
||||||
|
if(!mission.creatures.empty()) questName = CQuest::missionName(6);
|
||||||
|
if(mission.resources.nonZero()) questName = CQuest::missionName(7);
|
||||||
|
if(!mission.heroes.empty()) questName = CQuest::missionName(8);
|
||||||
|
if(!mission.players.empty()) questName = CQuest::missionName(9);
|
||||||
|
if(mission.daysPassed > 0 || !mission.heroClasses.empty()) questName = CQuest::missionName(11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CQuest::addKillTargetReplacements(MetaString &out) const
|
||||||
|
{
|
||||||
|
if(!heroName.empty())
|
||||||
|
out.replaceTextID(heroName);
|
||||||
|
if(stackToKill.type)
|
||||||
|
{
|
||||||
|
out.replaceCreatureName(stackToKill);
|
||||||
|
out.replaceRawString(VLC->generaltexth->arraytxt[147+stackDirection]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
|
void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
|
||||||
@@ -472,6 +340,7 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi
|
|||||||
handler.serializeStruct("firstVisitText", firstVisitText);
|
handler.serializeStruct("firstVisitText", firstVisitText);
|
||||||
handler.serializeStruct("nextVisitText", nextVisitText);
|
handler.serializeStruct("nextVisitText", nextVisitText);
|
||||||
handler.serializeStruct("completedText", completedText);
|
handler.serializeStruct("completedText", completedText);
|
||||||
|
handler.serializeBool("repeatedQuest", repeatedQuest, false);
|
||||||
|
|
||||||
if(!handler.saving)
|
if(!handler.saving)
|
||||||
{
|
{
|
||||||
@@ -480,86 +349,92 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi
|
|||||||
isCustomComplete = !completedText.empty();
|
isCustomComplete = !completedText.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::vector<std::string> MISSION_TYPE_JSON =
|
|
||||||
{
|
|
||||||
"None", "Level", "PrimaryStat", "KillHero", "KillCreature", "Artifact", "Army", "Resources", "Hero", "Player"
|
|
||||||
};
|
|
||||||
|
|
||||||
handler.serializeEnum("missionType", missionType, Emission::MISSION_NONE, MISSION_TYPE_JSON);
|
|
||||||
handler.serializeInt("timeLimit", lastDay, -1);
|
handler.serializeInt("timeLimit", lastDay, -1);
|
||||||
|
handler.serializeStruct("limiter", mission);
|
||||||
|
handler.serializeInstance("killTarget", killTarget, ObjectInstanceID::NONE);
|
||||||
|
|
||||||
switch (missionType)
|
if(!handler.saving) //compatibility with legacy vmaps
|
||||||
{
|
{
|
||||||
case MISSION_NONE:
|
std::string missionType = "None";
|
||||||
break;
|
handler.serializeString("missionType", missionType);
|
||||||
case MISSION_LEVEL:
|
if(missionType == "None")
|
||||||
handler.serializeInt("heroLevel", m13489val, -1);
|
return;
|
||||||
break;
|
|
||||||
case MISSION_PRIMARY_STAT:
|
if(missionType == "Level")
|
||||||
|
handler.serializeInt("heroLevel", mission.heroLevel);
|
||||||
|
|
||||||
|
if(missionType == "PrimaryStat")
|
||||||
{
|
{
|
||||||
auto primarySkills = handler.enterStruct("primarySkills");
|
auto primarySkills = handler.enterStruct("primarySkills");
|
||||||
if(!handler.saving)
|
|
||||||
m2stats.resize(GameConstants::PRIMARY_SKILLS);
|
|
||||||
|
|
||||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
||||||
handler.serializeInt(NPrimarySkill::names[i], m2stats[i], 0);
|
handler.serializeInt(NPrimarySkill::names[i], mission.primary[i], 0);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case MISSION_KILL_HERO:
|
if(missionType == "Artifact")
|
||||||
case MISSION_KILL_CREATURE:
|
handler.serializeIdArray<ArtifactID>("artifacts", mission.artifacts);
|
||||||
handler.serializeInstance<ui32>("killTarget", m13489val, static_cast<ui32>(-1));
|
|
||||||
break;
|
if(missionType == "Army")
|
||||||
case MISSION_ART:
|
|
||||||
//todo: ban artifacts
|
|
||||||
handler.serializeIdArray<ArtifactID>("artifacts", m5arts);
|
|
||||||
break;
|
|
||||||
case MISSION_ARMY:
|
|
||||||
{
|
{
|
||||||
auto a = handler.enterArray("creatures");
|
auto a = handler.enterArray("creatures");
|
||||||
a.serializeStruct(m6creatures);
|
a.serializeStruct(mission.creatures);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case MISSION_RESOURCES:
|
if(missionType == "Resources")
|
||||||
{
|
{
|
||||||
auto r = handler.enterStruct("resources");
|
auto r = handler.enterStruct("resources");
|
||||||
|
|
||||||
for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
|
for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
|
||||||
{
|
{
|
||||||
handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], m7resources[idx], 0);
|
handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], mission.resources[idx], 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case MISSION_HERO:
|
if(missionType == "Hero")
|
||||||
handler.serializeId<ui32, ui32, HeroTypeID>("hero", m13489val, 0);
|
{
|
||||||
break;
|
ui32 temp;
|
||||||
case MISSION_PLAYER:
|
handler.serializeId<ui32, ui32, HeroTypeID>("hero", temp, 0);
|
||||||
handler.serializeId<ui32, ui32, PlayerColor>("player", m13489val, PlayerColor::NEUTRAL);
|
mission.heroes.emplace_back(temp);
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
logGlobal->error("Invalid quest mission type");
|
if(missionType == "Player")
|
||||||
break;
|
{
|
||||||
|
ui32 temp;
|
||||||
|
handler.serializeId<ui32, ui32, PlayerColor>("player", temp, PlayerColor::NEUTRAL);
|
||||||
|
mission.players.emplace_back(temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IQuestObject::checkQuest(const CGHeroInstance* h) const
|
||||||
|
{
|
||||||
|
return quest->checkQuest(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IQuestObject::getVisitText(MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h) const
|
||||||
|
{
|
||||||
|
quest->getVisitText(text, components, FirstVisit, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IQuestObject::afterAddToMapCommon(CMap * map) const
|
||||||
|
{
|
||||||
|
map->addNewQuestInstance(quest);
|
||||||
|
}
|
||||||
|
|
||||||
void CGSeerHut::setObjToKill()
|
void CGSeerHut::setObjToKill()
|
||||||
{
|
{
|
||||||
if(quest->missionType == CQuest::MISSION_KILL_CREATURE)
|
if(getCreatureToKill(true))
|
||||||
{
|
{
|
||||||
quest->stackToKill = getCreatureToKill(false)->getStack(SlotID(0)); //FIXME: stacks tend to disappear (desync?) on server :?
|
quest->stackToKill = getCreatureToKill(false)->getStack(SlotID(0)); //FIXME: stacks tend to disappear (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(getHeroToKill(true))
|
||||||
{
|
{
|
||||||
quest->heroName = getHeroToKill(false)->getNameTranslated();
|
quest->heroName = getHeroToKill(false)->getNameTranslated();
|
||||||
quest->heroPortrait = getHeroToKill(false)->getPortraitSource();
|
quest->heroPortrait = getHeroToKill(false)->getPortraitSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
quest->getCompletionText(configuration.onSelect);
|
|
||||||
for(auto & i : configuration.info)
|
|
||||||
quest->getCompletionText(i.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGSeerHut::init(CRandomGenerator & rand)
|
void CGSeerHut::init(CRandomGenerator & rand)
|
||||||
@@ -582,28 +457,34 @@ void CGSeerHut::initObj(CRandomGenerator & rand)
|
|||||||
|
|
||||||
CRewardableObject::initObj(rand);
|
CRewardableObject::initObj(rand);
|
||||||
|
|
||||||
quest->progress = CQuest::NOT_ACTIVE;
|
setObjToKill();
|
||||||
if(quest->missionType)
|
quest->defineQuestName();
|
||||||
{
|
|
||||||
std::string questName = quest->missionName(quest->missionType);
|
|
||||||
|
|
||||||
if(!quest->isCustomFirst)
|
if(quest->mission == Rewardable::Limiter{} && quest->killTarget == ObjectInstanceID::NONE)
|
||||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", questName, quest->missionState(0), quest->textOption).get());
|
quest->isCompleted = true;
|
||||||
if(!quest->isCustomNext)
|
|
||||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", questName, quest->missionState(1), quest->textOption).get());
|
if(quest->questName == quest->missionName(0))
|
||||||
if(!quest->isCustomComplete)
|
{
|
||||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seerhut", "quest", questName, quest->missionState(2), quest->textOption).get());
|
quest->firstVisitText.appendTextID(TextIdentifier("core", "seehut", "empty", quest->completedOption).get());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
quest->progress = CQuest::COMPLETE;
|
if(!quest->isCustomFirst)
|
||||||
quest->firstVisitText.appendTextID(TextIdentifier("core", "seehut", "empty", quest->completedOption).get());
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quest->getCompletionText(configuration.onSelect);
|
||||||
|
for(auto & i : configuration.info)
|
||||||
|
quest->getCompletionText(i.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.replaceRawString(seerName);
|
text.replaceRawString(seerName);
|
||||||
}
|
}
|
||||||
@@ -611,13 +492,15 @@ void CGSeerHut::getRolloverText(MetaString &text, bool onHover) const
|
|||||||
std::string CGSeerHut::getHoverText(PlayerColor player) const
|
std::string CGSeerHut::getHoverText(PlayerColor player) const
|
||||||
{
|
{
|
||||||
std::string hoverName = getObjectName();
|
std::string hoverName = getObjectName();
|
||||||
if(ID == Obj::SEER_HUT && quest->progress != CQuest::NOT_ACTIVE)
|
if(ID == Obj::SEER_HUT && quest->activeForPlayers.count(player))
|
||||||
{
|
{
|
||||||
hoverName = VLC->generaltexth->allTexts[347];
|
hoverName = VLC->generaltexth->allTexts[347];
|
||||||
boost::algorithm::replace_first(hoverName, "%s", seerName);
|
boost::algorithm::replace_first(hoverName, "%s", seerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(quest->progress & quest->missionType) //rollover when the quest is active
|
if(quest->activeForPlayers.count(player)
|
||||||
|
&& (quest->mission != Rewardable::Limiter{}
|
||||||
|
|| quest->killTarget != ObjectInstanceID::NONE)) //rollover when the quest is active
|
||||||
{
|
{
|
||||||
MetaString ms;
|
MetaString ms;
|
||||||
getRolloverText (ms, true);
|
getRolloverText (ms, true);
|
||||||
@@ -626,48 +509,21 @@ std::string CGSeerHut::getHoverText(PlayerColor player) const
|
|||||||
return hoverName;
|
return hoverName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CQuest::addReplacements(MetaString &out, const std::string &base) const
|
void CGSeerHut::setPropertyDer(ui8 what, ui32 val)
|
||||||
{
|
|
||||||
switch(missionType)
|
|
||||||
{
|
|
||||||
case MISSION_KILL_CREATURE:
|
|
||||||
if(stackToKill.type)
|
|
||||||
{
|
|
||||||
out.replaceCreatureName(stackToKill);
|
|
||||||
if (std::count(base.begin(), base.end(), '%') == 2) //say where is placed monster
|
|
||||||
{
|
|
||||||
out.replaceRawString(VLC->generaltexth->arraytxt[147+stackDirection]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MISSION_KILL_HERO:
|
|
||||||
out.replaceTextID(heroName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IQuestObject::checkQuest(const CGHeroInstance* h) const
|
|
||||||
{
|
|
||||||
return quest->checkQuest(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IQuestObject::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
|
|
||||||
{
|
|
||||||
quest->getVisitText (text,components, isCustom, FirstVisit, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IQuestObject::afterAddToMapCommon(CMap * map) const
|
|
||||||
{
|
|
||||||
map->addNewQuestInstance(quest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGSeerHut::setPropertyDer (ui8 what, ui32 val)
|
|
||||||
{
|
{
|
||||||
switch(what)
|
switch(what)
|
||||||
{
|
{
|
||||||
case 10:
|
case CGSeerHut::SEERHUT_VISITED:
|
||||||
quest->progress = static_cast<CQuest::Eprogress>(val);
|
{
|
||||||
|
quest->activeForPlayers.emplace(val);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case CGSeerHut::SEERHUT_COMPLETE:
|
||||||
|
{
|
||||||
|
quest->isCompleted = val;
|
||||||
|
quest->activeForPlayers.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +532,7 @@ void CGSeerHut::newTurn(CRandomGenerator & rand) const
|
|||||||
CRewardableObject::newTurn(rand);
|
CRewardableObject::newTurn(rand);
|
||||||
if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up
|
if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up
|
||||||
{
|
{
|
||||||
cb->setObjProperty (id, CGSeerHut::OBJPROP_VISITED, CQuest::COMPLETE);
|
cb->setObjProperty (id, CGSeerHut::SEERHUT_COMPLETE, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,30 +540,24 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
{
|
{
|
||||||
InfoWindow iw;
|
InfoWindow iw;
|
||||||
iw.player = h->getOwner();
|
iw.player = h->getOwner();
|
||||||
if(quest->progress < CQuest::COMPLETE)
|
if(!quest->isCompleted)
|
||||||
{
|
{
|
||||||
bool firstVisit = !quest->progress;
|
bool firstVisit = !quest->activeForPlayers.count(h->getOwner());
|
||||||
bool failRequirements = !checkQuest(h);
|
bool failRequirements = !checkQuest(h);
|
||||||
bool isCustom = false;
|
|
||||||
|
|
||||||
if(firstVisit)
|
if(firstVisit)
|
||||||
{
|
{
|
||||||
isCustom = quest->isCustomFirst;
|
cb->setObjProperty(id, CGSeerHut::SEERHUT_VISITED, h->getOwner());
|
||||||
cb->setObjProperty(id, CGSeerHut::OBJPROP_VISITED, 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)
|
|
||||||
{
|
|
||||||
isCustom = quest->isCustomNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(firstVisit || failRequirements)
|
if(firstVisit || failRequirements)
|
||||||
{
|
{
|
||||||
getVisitText (iw.text, iw.components, isCustom, firstVisit, h);
|
getVisitText (iw.text, iw.components, firstVisit, h);
|
||||||
|
|
||||||
cb->showInfoDialog(&iw);
|
cb->showInfoDialog(&iw);
|
||||||
}
|
}
|
||||||
@@ -758,26 +608,19 @@ int CGSeerHut::checkDirection() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGSeerHut::completeQuest() const //reward
|
|
||||||
{
|
|
||||||
cb->setObjProperty(id, CGSeerHut::OBJPROP_VISITED, CQuest::COMPLETE); //mission complete
|
|
||||||
}
|
|
||||||
|
|
||||||
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->killTarget);
|
||||||
if(allowNull && !o)
|
if(allowNull && !o)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
assert(o && (o->ID == Obj::HERO || o->ID == Obj::PRISON));
|
|
||||||
return dynamic_cast<const CGHeroInstance *>(o);
|
return dynamic_cast<const CGHeroInstance *>(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
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->killTarget);
|
||||||
if(allowNull && !o)
|
if(allowNull && !o)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
assert(o && o->ID == Obj::MONSTER);
|
|
||||||
return dynamic_cast<const CGCreature *>(o);
|
return dynamic_cast<const CGCreature *>(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,7 +628,10 @@ void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer)
|
|||||||
{
|
{
|
||||||
CRewardableObject::blockingDialogAnswered(hero, answer);
|
CRewardableObject::blockingDialogAnswered(hero, answer);
|
||||||
if(answer)
|
if(answer)
|
||||||
completeQuest();
|
{
|
||||||
|
quest->completeQuest(cb, hero);
|
||||||
|
cb->setObjProperty(id, CGSeerHut::SEERHUT_COMPLETE, !quest->repeatedQuest); //mission complete
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGSeerHut::afterAddToMap(CMap* map)
|
void CGSeerHut::afterAddToMap(CMap* map)
|
||||||
@@ -874,10 +720,23 @@ void CGQuestGuard::init(CRandomGenerator & rand)
|
|||||||
|
|
||||||
configuration.info.push_back({});
|
configuration.info.push_back({});
|
||||||
configuration.info.back().visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
configuration.info.back().visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
||||||
configuration.info.back().reward.removeObject = true;
|
configuration.info.back().reward.removeObject = subID == 0 ? true : false;
|
||||||
configuration.canRefuse = true;
|
configuration.canRefuse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGQuestGuard::onHeroVisit(const CGHeroInstance * h) const
|
||||||
|
{
|
||||||
|
if(!quest->isCompleted)
|
||||||
|
CGSeerHut::onHeroVisit(h);
|
||||||
|
else
|
||||||
|
cb->setObjProperty(id, CGSeerHut::SEERHUT_COMPLETE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGQuestGuard::passableFor(PlayerColor color) const
|
||||||
|
{
|
||||||
|
return quest->isCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
void CGQuestGuard::serializeJsonOptions(JsonSerializeFormat & handler)
|
void CGQuestGuard::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
//quest only, do not call base class
|
//quest only, do not call base class
|
||||||
@@ -938,12 +797,12 @@ void CGBorderGuard::initObj(CRandomGenerator & rand)
|
|||||||
blockVisit = true;
|
blockVisit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
|
void CGBorderGuard::getVisitText(MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h) const
|
||||||
{
|
{
|
||||||
text.appendLocalString(EMetaText::ADVOB_TXT,18);
|
text.appendLocalString(EMetaText::ADVOB_TXT, 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const
|
void CGBorderGuard::getRolloverText(MetaString &text, bool onHover) const
|
||||||
{
|
{
|
||||||
if (!onHover)
|
if (!onHover)
|
||||||
{
|
{
|
||||||
|
@@ -19,47 +19,21 @@ class CGCreature;
|
|||||||
|
|
||||||
class DLL_LINKAGE CQuest final
|
class DLL_LINKAGE CQuest final
|
||||||
{
|
{
|
||||||
mutable std::unordered_map<ArtifactID, unsigned, ArtifactID::hash> artifactsRequirements; // artifact ID -> required count
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Emission {
|
|
||||||
MISSION_NONE = 0,
|
|
||||||
MISSION_LEVEL = 1,
|
|
||||||
MISSION_PRIMARY_STAT = 2,
|
|
||||||
MISSION_KILL_HERO = 3,
|
|
||||||
MISSION_KILL_CREATURE = 4,
|
|
||||||
MISSION_ART = 5,
|
|
||||||
MISSION_ARMY = 6,
|
|
||||||
MISSION_RESOURCES = 7,
|
|
||||||
MISSION_HERO = 8,
|
|
||||||
MISSION_PLAYER = 9,
|
|
||||||
MISSION_HOTA_MULTI = 10,
|
|
||||||
// end of H3 missions
|
|
||||||
MISSION_KEYMASTER = 100,
|
|
||||||
MISSION_HOTA_HERO_CLASS = 101,
|
|
||||||
MISSION_HOTA_REACH_DATE = 102
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Eprogress {
|
static const std::string & missionName(int index);
|
||||||
NOT_ACTIVE,
|
static const std::string & missionState(int index);
|
||||||
IN_PROGRESS,
|
|
||||||
COMPLETE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const std::string & missionName(Emission mission);
|
std::string questName;
|
||||||
static const std::string & missionState(int index);
|
|
||||||
|
|
||||||
si32 qid; //unique quest id for serialization / identification
|
si32 qid; //unique quest id for serialization / identification
|
||||||
|
|
||||||
Emission missionType;
|
|
||||||
Eprogress progress;
|
|
||||||
si32 lastDay; //after this day (first day is 0) mission cannot be completed; if -1 - no limit
|
si32 lastDay; //after this day (first day is 0) mission cannot be completed; if -1 - no limit
|
||||||
|
ObjectInstanceID killTarget;
|
||||||
ui32 m13489val;
|
Rewardable::Limiter mission;
|
||||||
std::vector<ui32> m2stats;
|
bool repeatedQuest;
|
||||||
std::vector<ArtifactID> m5arts; // artifact IDs. Add IDs through addArtifactID(), not directly to the field.
|
bool isCompleted;
|
||||||
std::vector<CStackBasicDescriptor> m6creatures; //pair[cre id, cre count], CreatureSet info irrelevant
|
std::set<PlayerColor> activeForPlayers;
|
||||||
TResources m7resources;
|
|
||||||
|
|
||||||
// following fields are used only for kill creature/hero missions, the original
|
// following fields are used only for kill creature/hero missions, the original
|
||||||
// objects became inaccessible after their removal, so we need to store info
|
// objects became inaccessible after their removal, so we need to store info
|
||||||
@@ -79,13 +53,14 @@ public:
|
|||||||
CQuest(); //TODO: Remove constructor
|
CQuest(); //TODO: Remove constructor
|
||||||
|
|
||||||
static bool checkMissionArmy(const CQuest * q, const CCreatureSet * army);
|
static bool checkMissionArmy(const CQuest * q, const CCreatureSet * army);
|
||||||
virtual bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
|
virtual bool checkQuest(const CGHeroInstance * h) const; //determines whether the quest is complete or not
|
||||||
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
virtual void getVisitText(MetaString &text, std::vector<Component> & components, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
||||||
virtual void getCompletionText(MetaString &text) const;
|
virtual void getCompletionText(MetaString &text) const;
|
||||||
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
|
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
|
||||||
virtual void completeQuest (const CGHeroInstance * h) const {};
|
virtual void completeQuest(IGameCallback *, const CGHeroInstance * h) const;
|
||||||
virtual void addReplacements(MetaString &out, const std::string &base) const;
|
virtual void addTextReplacements(MetaString &out, std::vector<Component> & components) const;
|
||||||
void addArtifactID(const ArtifactID & id);
|
virtual void addKillTargetReplacements(MetaString &out) const;
|
||||||
|
void defineQuestName();
|
||||||
|
|
||||||
bool operator== (const CQuest & quest) const
|
bool operator== (const CQuest & quest) const
|
||||||
{
|
{
|
||||||
@@ -95,14 +70,9 @@ public:
|
|||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & qid;
|
h & qid;
|
||||||
h & missionType;
|
h & isCompleted;
|
||||||
h & progress;
|
h & activeForPlayers;
|
||||||
h & lastDay;
|
h & lastDay;
|
||||||
h & m13489val;
|
|
||||||
h & m2stats;
|
|
||||||
h & m5arts;
|
|
||||||
h & m6creatures;
|
|
||||||
h & m7resources;
|
|
||||||
h & textOption;
|
h & textOption;
|
||||||
h & stackToKill;
|
h & stackToKill;
|
||||||
h & stackDirection;
|
h & stackDirection;
|
||||||
@@ -115,6 +85,9 @@ public:
|
|||||||
h & isCustomNext;
|
h & isCustomNext;
|
||||||
h & isCustomComplete;
|
h & isCustomComplete;
|
||||||
h & completedOption;
|
h & completedOption;
|
||||||
|
h & questName;
|
||||||
|
h & mission;
|
||||||
|
h & killTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
|
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
|
||||||
@@ -128,7 +101,7 @@ public:
|
|||||||
///Information about quest should remain accessible even if IQuestObject removed from map
|
///Information about quest should remain accessible even if IQuestObject removed from map
|
||||||
///All CQuest objects are freed in CMap destructor
|
///All CQuest objects are freed in CMap destructor
|
||||||
virtual ~IQuestObject() = default;
|
virtual ~IQuestObject() = default;
|
||||||
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
|
||||||
virtual bool checkQuest (const CGHeroInstance * h) const;
|
virtual bool checkQuest (const CGHeroInstance * h) const;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
@@ -156,8 +129,6 @@ public:
|
|||||||
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
|
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
|
||||||
const CGCreature *getCreatureToKill(bool allowNull = false) const;
|
const CGCreature *getCreatureToKill(bool allowNull = false) const;
|
||||||
void getRolloverText (MetaString &text, bool onHover) const;
|
void getRolloverText (MetaString &text, bool onHover) const;
|
||||||
void finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects
|
|
||||||
virtual void completeQuest() const;
|
|
||||||
|
|
||||||
void afterAddToMap(CMap * map) override;
|
void afterAddToMap(CMap * map) override;
|
||||||
|
|
||||||
@@ -168,7 +139,8 @@ public:
|
|||||||
h & seerName;
|
h & seerName;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
static constexpr int OBJPROP_VISITED = 10;
|
static constexpr int SEERHUT_VISITED = 10;
|
||||||
|
static constexpr int SEERHUT_COMPLETE = 11;
|
||||||
|
|
||||||
void setPropertyDer(ui8 what, ui32 val) override;
|
void setPropertyDer(ui8 what, ui32 val) override;
|
||||||
|
|
||||||
@@ -180,6 +152,9 @@ class DLL_LINKAGE CGQuestGuard : public CGSeerHut
|
|||||||
public:
|
public:
|
||||||
void init(CRandomGenerator & rand) override;
|
void init(CRandomGenerator & rand) override;
|
||||||
|
|
||||||
|
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||||
|
bool passableFor(PlayerColor color) const override;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & static_cast<CGSeerHut&>(*this);
|
h & static_cast<CGSeerHut&>(*this);
|
||||||
@@ -228,7 +203,7 @@ public:
|
|||||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||||
|
|
||||||
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const override;
|
void getVisitText (MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h = nullptr) const override;
|
||||||
void getRolloverText (MetaString &text, bool onHover) const;
|
void getRolloverText (MetaString &text, bool onHover) const;
|
||||||
bool checkQuest (const CGHeroInstance * h) const override;
|
bool checkQuest (const CGHeroInstance * h) const override;
|
||||||
|
|
||||||
|
@@ -144,6 +144,9 @@ ui8 CMapHeader::levels() const
|
|||||||
|
|
||||||
void CMapHeader::registerMapStrings()
|
void CMapHeader::registerMapStrings()
|
||||||
{
|
{
|
||||||
|
VLC->generaltexth->removeSubContainer(*this);
|
||||||
|
VLC->generaltexth->addSubContainer(*this);
|
||||||
|
|
||||||
//get supported languages. Assuming that translation containing most strings is the base language
|
//get supported languages. Assuming that translation containing most strings is the base language
|
||||||
std::set<std::string> mapLanguages, mapBaseLanguages;
|
std::set<std::string> mapLanguages, mapBaseLanguages;
|
||||||
int maxStrings = 0;
|
int maxStrings = 0;
|
||||||
|
@@ -105,7 +105,10 @@ std::string CMapInfo::getNameTranslated() const
|
|||||||
if(campaign && !campaign->getNameTranslated().empty())
|
if(campaign && !campaign->getNameTranslated().empty())
|
||||||
return campaign->getNameTranslated();
|
return campaign->getNameTranslated();
|
||||||
else if(mapHeader && !mapHeader->name.empty())
|
else if(mapHeader && !mapHeader->name.empty())
|
||||||
|
{
|
||||||
|
mapHeader->registerMapStrings();
|
||||||
return mapHeader->name.toString();
|
return mapHeader->name.toString();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return VLC->generaltexth->allTexts[508];
|
return VLC->generaltexth->allTexts[508];
|
||||||
}
|
}
|
||||||
|
@@ -1830,6 +1830,7 @@ CGObjectInstance * CMapLoaderH3M::readSeerHut(const int3 & position, const Objec
|
|||||||
if(features.levelHOTA3)
|
if(features.levelHOTA3)
|
||||||
{
|
{
|
||||||
uint32_t repeateableQuestsCount = reader->readUInt32();
|
uint32_t repeateableQuestsCount = reader->readUInt32();
|
||||||
|
hut->quest->repeatedQuest = repeateableQuestsCount != 0;
|
||||||
|
|
||||||
if(repeateableQuestsCount != 0)
|
if(repeateableQuestsCount != 0)
|
||||||
logGlobal->warn("Map '%s': Seer Hut at %s - %d repeatable quests are not implemented!", mapName, position.toString(), repeateableQuestsCount);
|
logGlobal->warn("Map '%s': Seer Hut at %s - %d repeatable quests are not implemented!", mapName, position.toString(), repeateableQuestsCount);
|
||||||
@@ -1858,11 +1859,30 @@ enum class ESeerHutRewardType : uint8_t
|
|||||||
CREATURE = 10,
|
CREATURE = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EQuestMission {
|
||||||
|
NONE = 0,
|
||||||
|
LEVEL = 1,
|
||||||
|
PRIMARY_SKILL = 2,
|
||||||
|
KILL_HERO = 3,
|
||||||
|
KILL_CREATURE = 4,
|
||||||
|
ARTIFACT = 5,
|
||||||
|
ARMY = 6,
|
||||||
|
RESOURCES = 7,
|
||||||
|
HERO = 8,
|
||||||
|
PLAYER = 9,
|
||||||
|
HOTA_MULTI = 10,
|
||||||
|
// end of H3 missions
|
||||||
|
KEYMASTER = 100,
|
||||||
|
HOTA_HERO_CLASS = 101,
|
||||||
|
HOTA_REACH_DATE = 102
|
||||||
|
};
|
||||||
|
|
||||||
void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, const ObjectInstanceID & idToBeGiven)
|
void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, const ObjectInstanceID & idToBeGiven)
|
||||||
{
|
{
|
||||||
|
EQuestMission missionType = EQuestMission::NONE;
|
||||||
if(features.levelAB)
|
if(features.levelAB)
|
||||||
{
|
{
|
||||||
readQuest(hut, position);
|
missionType = static_cast<EQuestMission>(readQuest(hut, position));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1871,12 +1891,8 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
|||||||
if(artID != ArtifactID::NONE)
|
if(artID != ArtifactID::NONE)
|
||||||
{
|
{
|
||||||
//not none quest
|
//not none quest
|
||||||
hut->quest->addArtifactID(artID);
|
hut->quest->mission.artifacts.push_back(artID);
|
||||||
hut->quest->missionType = CQuest::MISSION_ART;
|
missionType = EQuestMission::ARTIFACT;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hut->quest->missionType = CQuest::MISSION_NONE;
|
|
||||||
}
|
}
|
||||||
hut->quest->lastDay = -1; //no timeout
|
hut->quest->lastDay = -1; //no timeout
|
||||||
hut->quest->isCustomFirst = false;
|
hut->quest->isCustomFirst = false;
|
||||||
@@ -1884,7 +1900,7 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
|||||||
hut->quest->isCustomComplete = false;
|
hut->quest->isCustomComplete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hut->quest->missionType)
|
if(missionType != EQuestMission::NONE)
|
||||||
{
|
{
|
||||||
auto rewardType = static_cast<ESeerHutRewardType>(reader->readUInt8());
|
auto rewardType = static_cast<ESeerHutRewardType>(reader->readUInt8());
|
||||||
Rewardable::VisitInfo vinfo;
|
Rewardable::VisitInfo vinfo;
|
||||||
@@ -1976,91 +1992,91 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
int CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||||
{
|
{
|
||||||
guard->quest->missionType = static_cast<CQuest::Emission>(reader->readUInt8());
|
auto missionId = reader->readUInt8();
|
||||||
|
|
||||||
switch(guard->quest->missionType)
|
switch(static_cast<EQuestMission>(missionId))
|
||||||
{
|
{
|
||||||
case CQuest::MISSION_NONE:
|
case EQuestMission::NONE:
|
||||||
return;
|
return missionId;
|
||||||
case CQuest::MISSION_PRIMARY_STAT:
|
case EQuestMission::PRIMARY_SKILL:
|
||||||
{
|
{
|
||||||
guard->quest->m2stats.resize(4);
|
|
||||||
for(int x = 0; x < 4; ++x)
|
for(int x = 0; x < 4; ++x)
|
||||||
{
|
{
|
||||||
guard->quest->m2stats[x] = reader->readUInt8();
|
guard->quest->mission.primary[x] = reader->readUInt8();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CQuest::MISSION_LEVEL:
|
|
||||||
case CQuest::MISSION_KILL_HERO:
|
|
||||||
case CQuest::MISSION_KILL_CREATURE:
|
|
||||||
{
|
|
||||||
guard->quest->m13489val = reader->readUInt32();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_ART:
|
case EQuestMission::LEVEL:
|
||||||
|
{
|
||||||
|
guard->quest->mission.heroLevel = reader->readUInt32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EQuestMission::KILL_HERO:
|
||||||
|
case EQuestMission::KILL_CREATURE:
|
||||||
|
{
|
||||||
|
guard->quest->killTarget = ObjectInstanceID(reader->readUInt32());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EQuestMission::ARTIFACT:
|
||||||
{
|
{
|
||||||
int artNumber = reader->readUInt8();
|
int artNumber = reader->readUInt8();
|
||||||
for(int yy = 0; yy < artNumber; ++yy)
|
for(int yy = 0; yy < artNumber; ++yy)
|
||||||
{
|
{
|
||||||
auto artid = reader->readArtifact();
|
auto artid = reader->readArtifact();
|
||||||
guard->quest->addArtifactID(artid);
|
guard->quest->mission.artifacts.push_back(artid);
|
||||||
map->allowedArtifact[artid] = false; //these are unavailable for random generation
|
map->allowedArtifact[artid] = false; //these are unavailable for random generation
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_ARMY:
|
case EQuestMission::ARMY:
|
||||||
{
|
{
|
||||||
int typeNumber = reader->readUInt8();
|
int typeNumber = reader->readUInt8();
|
||||||
guard->quest->m6creatures.resize(typeNumber);
|
guard->quest->mission.creatures.resize(typeNumber);
|
||||||
for(int hh = 0; hh < typeNumber; ++hh)
|
for(int hh = 0; hh < typeNumber; ++hh)
|
||||||
{
|
{
|
||||||
guard->quest->m6creatures[hh].type = VLC->creh->objects[reader->readCreature()];
|
guard->quest->mission.creatures[hh].type = VLC->creh->objects[reader->readCreature()];
|
||||||
guard->quest->m6creatures[hh].count = reader->readUInt16();
|
guard->quest->mission.creatures[hh].count = reader->readUInt16();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_RESOURCES:
|
case EQuestMission::RESOURCES:
|
||||||
{
|
{
|
||||||
for(int x = 0; x < 7; ++x)
|
for(int x = 0; x < 7; ++x)
|
||||||
guard->quest->m7resources[x] = reader->readUInt32();
|
guard->quest->mission.resources[x] = reader->readUInt32();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_HERO:
|
case EQuestMission::HERO:
|
||||||
{
|
{
|
||||||
guard->quest->m13489val = reader->readHero().getNum();
|
guard->quest->mission.heroes.push_back(reader->readHero());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_PLAYER:
|
case EQuestMission::PLAYER:
|
||||||
{
|
{
|
||||||
guard->quest->m13489val = reader->readPlayer().getNum();
|
guard->quest->mission.players.push_back(reader->readPlayer());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CQuest::MISSION_HOTA_MULTI:
|
case EQuestMission::HOTA_MULTI:
|
||||||
{
|
{
|
||||||
uint32_t missionSubID = reader->readUInt32();
|
uint32_t missionSubID = reader->readUInt32();
|
||||||
|
|
||||||
if(missionSubID == 0)
|
if(missionSubID == 0)
|
||||||
{
|
{
|
||||||
guard->quest->missionType = CQuest::MISSION_NONE; //TODO: CQuest::MISSION_HOTA_HERO_CLASS;
|
missionId = int(EQuestMission::HOTA_HERO_CLASS);
|
||||||
std::set<HeroClassID> heroClasses;
|
std::set<HeroClassID> heroClasses;
|
||||||
reader->readBitmaskHeroClassesSized(heroClasses, false);
|
reader->readBitmaskHeroClassesSized(heroClasses, false);
|
||||||
|
for(auto & hc : heroClasses)
|
||||||
logGlobal->warn("Map '%s': Quest at %s 'Belong to one of %d classes' is not implemented!", mapName, position.toString(), heroClasses.size());
|
guard->quest->mission.heroClasses.push_back(hc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(missionSubID == 1)
|
if(missionSubID == 1)
|
||||||
{
|
{
|
||||||
guard->quest->missionType = CQuest::MISSION_NONE; //TODO: CQuest::MISSION_HOTA_REACH_DATE;
|
missionId = int(EQuestMission::HOTA_REACH_DATE);
|
||||||
uint32_t daysPassed = reader->readUInt32();
|
guard->quest->mission.daysPassed = reader->readUInt32() + 1;
|
||||||
|
|
||||||
logGlobal->warn("Map '%s': Quest at %s 'Wait till %d days passed' is not implemented!", mapName, position.toString(), daysPassed);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -2076,6 +2092,7 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
|||||||
guard->quest->isCustomFirst = !guard->quest->firstVisitText.empty();
|
guard->quest->isCustomFirst = !guard->quest->firstVisitText.empty();
|
||||||
guard->quest->isCustomNext = !guard->quest->nextVisitText.empty();
|
guard->quest->isCustomNext = !guard->quest->nextVisitText.empty();
|
||||||
guard->quest->isCustomComplete = !guard->quest->completedText.empty();
|
guard->quest->isCustomComplete = !guard->quest->completedText.empty();
|
||||||
|
return missionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate)
|
CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate)
|
||||||
|
@@ -204,7 +204,7 @@ private:
|
|||||||
*
|
*
|
||||||
* @param guard the quest guard where that quest should be applied to
|
* @param guard the quest guard where that quest should be applied to
|
||||||
*/
|
*/
|
||||||
void readQuest(IQuestObject * guard, const int3 & position);
|
int readQuest(IQuestObject * guard, const int3 & position);
|
||||||
|
|
||||||
void readSeerHutQuest(CGSeerHut * hut, const int3 & position, const ObjectInstanceID & idToBeGiven);
|
void readSeerHutQuest(CGSeerHut * hut, const int3 & position, const ObjectInstanceID & idToBeGiven);
|
||||||
|
|
||||||
|
@@ -123,6 +123,10 @@ void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRan
|
|||||||
limiter.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
|
limiter.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
|
||||||
limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
|
limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
|
||||||
|
|
||||||
|
limiter.players = JsonRandom::loadColors(source["colors"], rng);
|
||||||
|
limiter.heroes = JsonRandom::loadHeroes(source["heroes"], rng);
|
||||||
|
limiter.heroClasses = JsonRandom::loadHeroClasses(source["heroClasses"], rng);
|
||||||
|
|
||||||
limiter.allOf = configureSublimiters(object, rng, source["allOf"] );
|
limiter.allOf = configureSublimiters(object, rng, source["allOf"] );
|
||||||
limiter.anyOf = configureSublimiters(object, rng, source["anyOf"] );
|
limiter.anyOf = configureSublimiters(object, rng, source["anyOf"] );
|
||||||
limiter.noneOf = configureSublimiters(object, rng, source["noneOf"] );
|
limiter.noneOf = configureSublimiters(object, rng, source["noneOf"] );
|
||||||
|
@@ -16,7 +16,9 @@
|
|||||||
#include "../mapObjects/CGHeroInstance.h"
|
#include "../mapObjects/CGHeroInstance.h"
|
||||||
#include "../serializer/JsonSerializeFormat.h"
|
#include "../serializer/JsonSerializeFormat.h"
|
||||||
#include "../constants/StringConstants.h"
|
#include "../constants/StringConstants.h"
|
||||||
|
#include "../CHeroHandler.h"
|
||||||
#include "../CSkillHandler.h"
|
#include "../CSkillHandler.h"
|
||||||
|
#include "../ArtifactUtils.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@@ -24,7 +26,7 @@ Rewardable::Limiter::Limiter()
|
|||||||
: dayOfWeek(0)
|
: dayOfWeek(0)
|
||||||
, daysPassed(0)
|
, daysPassed(0)
|
||||||
, heroExperience(0)
|
, heroExperience(0)
|
||||||
, heroLevel(0)
|
, heroLevel(-1)
|
||||||
, manaPercentage(0)
|
, manaPercentage(0)
|
||||||
, manaPoints(0)
|
, manaPoints(0)
|
||||||
, primary(GameConstants::PRIMARY_SKILLS, 0)
|
, primary(GameConstants::PRIMARY_SKILLS, 0)
|
||||||
@@ -33,6 +35,33 @@ Rewardable::Limiter::Limiter()
|
|||||||
|
|
||||||
Rewardable::Limiter::~Limiter() = default;
|
Rewardable::Limiter::~Limiter() = default;
|
||||||
|
|
||||||
|
bool operator==(const Rewardable::Limiter & l, const Rewardable::Limiter & r)
|
||||||
|
{
|
||||||
|
return l.dayOfWeek == r.dayOfWeek
|
||||||
|
&& l.daysPassed == r.daysPassed
|
||||||
|
&& l.heroLevel == r.heroLevel
|
||||||
|
&& l.heroExperience == r.heroExperience
|
||||||
|
&& l.manaPoints == r.manaPoints
|
||||||
|
&& l.manaPercentage == r.manaPercentage
|
||||||
|
&& l.secondary == r.secondary
|
||||||
|
&& l.creatures == r.creatures
|
||||||
|
&& l.spells == r.spells
|
||||||
|
&& l.artifacts == r.artifacts
|
||||||
|
&& l.players == r.players
|
||||||
|
&& l.heroes == r.heroes
|
||||||
|
&& l.heroClasses == r.heroClasses
|
||||||
|
&& l.resources == r.resources
|
||||||
|
&& l.primary == r.primary
|
||||||
|
&& l.noneOf == r.noneOf
|
||||||
|
&& l.allOf == r.allOf
|
||||||
|
&& l.anyOf == r.anyOf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Rewardable::Limiter & l, const Rewardable::Limiter & r)
|
||||||
|
{
|
||||||
|
return !(l == r);
|
||||||
|
}
|
||||||
|
|
||||||
bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
if(dayOfWeek != 0)
|
if(dayOfWeek != 0)
|
||||||
@@ -93,12 +122,34 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto & art : artifacts)
|
|
||||||
{
|
{
|
||||||
if (!hero->hasArt(art))
|
std::unordered_map<ArtifactID, unsigned int, ArtifactID::hash> artifactsRequirements; // artifact ID -> required count
|
||||||
|
for(const auto & art : artifacts)
|
||||||
|
++artifactsRequirements[art];
|
||||||
|
|
||||||
|
size_t reqSlots = 0;
|
||||||
|
for(const auto & elem : artifactsRequirements)
|
||||||
|
{
|
||||||
|
// check required amount of artifacts
|
||||||
|
if(hero->getArtPosCount(elem.first, false, true, true) < elem.second)
|
||||||
|
return false;
|
||||||
|
if(!hero->hasArt(elem.first))
|
||||||
|
reqSlots += hero->getAssemblyByConstituent(elem.first)->getPartsInfo().size() - 2;
|
||||||
|
}
|
||||||
|
if(!ArtifactUtils::isBackpackFreeSlots(hero, reqSlots))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!players.empty() && !vstd::contains(players, hero->getOwner()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!heroes.empty() && !vstd::contains(heroes, hero->type->getId()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!heroClasses.empty() && !vstd::contains(heroClasses, hero->type->heroClass->getId()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
for(const auto & sublimiter : noneOf)
|
for(const auto & sublimiter : noneOf)
|
||||||
{
|
{
|
||||||
if (sublimiter->heroAllowed(hero))
|
if (sublimiter->heroAllowed(hero))
|
||||||
@@ -122,6 +173,56 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rewardable::Limiter::loadComponents(std::vector<Component> & comps,
|
||||||
|
const CGHeroInstance * h) const
|
||||||
|
{
|
||||||
|
if (heroExperience)
|
||||||
|
comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast<si32>(h->calculateXp(heroExperience)), 0);
|
||||||
|
|
||||||
|
if (heroLevel > 0)
|
||||||
|
comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0);
|
||||||
|
|
||||||
|
if (manaPoints || manaPercentage > 0)
|
||||||
|
{
|
||||||
|
int absoluteMana = h->manaLimit() ? (manaPercentage * h->mana / h->manaLimit() / 100) : 0;
|
||||||
|
comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, absoluteMana + manaPoints, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i=0; i<primary.size(); i++)
|
||||||
|
{
|
||||||
|
if (primary[i] != 0)
|
||||||
|
comps.emplace_back(Component::EComponentType::PRIM_SKILL, static_cast<ui16>(i), primary[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto & entry : secondary)
|
||||||
|
comps.emplace_back(Component::EComponentType::SEC_SKILL, entry.first, entry.second, 0);
|
||||||
|
|
||||||
|
for(const auto & entry : artifacts)
|
||||||
|
comps.emplace_back(Component::EComponentType::ARTIFACT, entry, 1, 0);
|
||||||
|
|
||||||
|
for(const auto & entry : spells)
|
||||||
|
comps.emplace_back(Component::EComponentType::SPELL, entry, 1, 0);
|
||||||
|
|
||||||
|
for(const auto & entry : creatures)
|
||||||
|
comps.emplace_back(Component::EComponentType::CREATURE, entry.type->getId(), entry.count, 0);
|
||||||
|
|
||||||
|
for(const auto & entry : players)
|
||||||
|
comps.emplace_back(Component::EComponentType::FLAG, entry, 0, 0);
|
||||||
|
|
||||||
|
//FIXME: portrait may not match hero, if custom portrait was set in map editor
|
||||||
|
for(const auto & entry : heroes)
|
||||||
|
comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroTypes()->getById(entry)->getIconIndex(), 0, 0);
|
||||||
|
|
||||||
|
for(const auto & entry : heroClasses)
|
||||||
|
comps.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroClasses()->getById(entry)->getIconIndex(), 0, 0);
|
||||||
|
|
||||||
|
for (size_t i=0; i<resources.size(); i++)
|
||||||
|
{
|
||||||
|
if (resources[i] !=0)
|
||||||
|
comps.emplace_back(Component::EComponentType::RESOURCE, static_cast<ui16>(i), resources[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler)
|
void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
handler.serializeInt("dayOfWeek", dayOfWeek);
|
handler.serializeInt("dayOfWeek", dayOfWeek);
|
||||||
@@ -130,6 +231,9 @@ void Rewardable::Limiter::serializeJson(JsonSerializeFormat & handler)
|
|||||||
handler.serializeInt("manaPercentage", manaPercentage);
|
handler.serializeInt("manaPercentage", manaPercentage);
|
||||||
handler.serializeInt("heroExperience", heroExperience);
|
handler.serializeInt("heroExperience", heroExperience);
|
||||||
handler.serializeInt("heroLevel", heroLevel);
|
handler.serializeInt("heroLevel", heroLevel);
|
||||||
|
handler.serializeIdArray("heroes", heroes);
|
||||||
|
handler.serializeIdArray("heroClasses", heroClasses);
|
||||||
|
handler.serializeIdArray("colors", players);
|
||||||
handler.serializeInt("manaPoints", manaPoints);
|
handler.serializeInt("manaPoints", manaPoints);
|
||||||
handler.serializeIdArray("artifacts", artifacts);
|
handler.serializeIdArray("artifacts", artifacts);
|
||||||
handler.enterArray("creatures").serializeStruct(creatures);
|
handler.enterArray("creatures").serializeStruct(creatures);
|
||||||
|
@@ -17,6 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
class CStackBasicDescriptor;
|
class CStackBasicDescriptor;
|
||||||
|
struct Component;
|
||||||
|
|
||||||
namespace Rewardable {
|
namespace Rewardable {
|
||||||
|
|
||||||
@@ -25,8 +26,7 @@ using LimitersList = std::vector<std::shared_ptr<Rewardable::Limiter>>;
|
|||||||
|
|
||||||
/// Limiters of rewards. Rewards will be granted to hero only if he satisfies requirements
|
/// Limiters of rewards. Rewards will be granted to hero only if he satisfies requirements
|
||||||
/// Note: for this is only a test - it won't remove anything from hero (e.g. artifacts or creatures)
|
/// Note: for this is only a test - it won't remove anything from hero (e.g. artifacts or creatures)
|
||||||
/// NOTE: in future should (partially) replace seer hut/quest guard quests checks
|
struct DLL_LINKAGE Limiter final
|
||||||
struct DLL_LINKAGE Limiter
|
|
||||||
{
|
{
|
||||||
/// day of week, unused if 0, 1-7 will test for current day of week
|
/// day of week, unused if 0, 1-7 will test for current day of week
|
||||||
si32 dayOfWeek;
|
si32 dayOfWeek;
|
||||||
@@ -52,7 +52,7 @@ struct DLL_LINKAGE Limiter
|
|||||||
std::map<SecondarySkill, si32> secondary;
|
std::map<SecondarySkill, si32> secondary;
|
||||||
|
|
||||||
/// artifacts that hero needs to have (equipped or in backpack) to trigger this
|
/// artifacts that hero needs to have (equipped or in backpack) to trigger this
|
||||||
/// Note: does not checks for multiple copies of the same arts
|
/// checks for artifacts copies if same artifact id is included multiple times
|
||||||
std::vector<ArtifactID> artifacts;
|
std::vector<ArtifactID> artifacts;
|
||||||
|
|
||||||
/// Spells that hero must have in the spellbook
|
/// Spells that hero must have in the spellbook
|
||||||
@@ -61,6 +61,13 @@ struct DLL_LINKAGE Limiter
|
|||||||
/// creatures that hero needs to have
|
/// creatures that hero needs to have
|
||||||
std::vector<CStackBasicDescriptor> creatures;
|
std::vector<CStackBasicDescriptor> creatures;
|
||||||
|
|
||||||
|
/// only heroes/hero classes from list could pass limiter
|
||||||
|
std::vector<HeroTypeID> heroes;
|
||||||
|
std::vector<HeroClassID> heroClasses;
|
||||||
|
|
||||||
|
/// only player colors can pass limiter
|
||||||
|
std::vector<PlayerColor> players;
|
||||||
|
|
||||||
/// sub-limiters, all must pass for this limiter to pass
|
/// sub-limiters, all must pass for this limiter to pass
|
||||||
LimitersList allOf;
|
LimitersList allOf;
|
||||||
|
|
||||||
@@ -75,6 +82,10 @@ struct DLL_LINKAGE Limiter
|
|||||||
|
|
||||||
bool heroAllowed(const CGHeroInstance * hero) const;
|
bool heroAllowed(const CGHeroInstance * hero) const;
|
||||||
|
|
||||||
|
/// Generates list of components that describes reward for a specific hero
|
||||||
|
void loadComponents(std::vector<Component> & comps,
|
||||||
|
const CGHeroInstance * h) const;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & dayOfWeek;
|
h & dayOfWeek;
|
||||||
@@ -88,6 +99,9 @@ struct DLL_LINKAGE Limiter
|
|||||||
h & secondary;
|
h & secondary;
|
||||||
h & artifacts;
|
h & artifacts;
|
||||||
h & creatures;
|
h & creatures;
|
||||||
|
h & heroes;
|
||||||
|
h & heroClasses;
|
||||||
|
h & players;
|
||||||
h & allOf;
|
h & allOf;
|
||||||
h & anyOf;
|
h & anyOf;
|
||||||
h & noneOf;
|
h & noneOf;
|
||||||
@@ -98,4 +112,7 @@ struct DLL_LINKAGE Limiter
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DLL_LINKAGE operator== (const Rewardable::Limiter & l, const Rewardable::Limiter & r);
|
||||||
|
bool DLL_LINKAGE operator!= (const Rewardable::Limiter & l, const Rewardable::Limiter & r);
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@@ -29,7 +29,7 @@ using RewardsList = std::vector<std::shared_ptr<Rewardable::Reward>>;
|
|||||||
|
|
||||||
/// Reward that can be granted to a hero
|
/// Reward that can be granted to a hero
|
||||||
/// NOTE: eventually should replace seer hut rewards and events/pandoras
|
/// NOTE: eventually should replace seer hut rewards and events/pandoras
|
||||||
struct DLL_LINKAGE Reward
|
struct DLL_LINKAGE Reward final
|
||||||
{
|
{
|
||||||
/// resources that will be given to player
|
/// resources that will be given to player
|
||||||
TResources resources;
|
TResources resources;
|
||||||
@@ -78,7 +78,7 @@ struct DLL_LINKAGE Reward
|
|||||||
bool removeObject;
|
bool removeObject;
|
||||||
|
|
||||||
/// Generates list of components that describes reward for a specific hero
|
/// Generates list of components that describes reward for a specific hero
|
||||||
virtual void loadComponents(std::vector<Component> & comps,
|
void loadComponents(std::vector<Component> & comps,
|
||||||
const CGHeroInstance * h) const;
|
const CGHeroInstance * h) const;
|
||||||
|
|
||||||
Component getDisplayedComponent(const CGHeroInstance * h) const;
|
Component getDisplayedComponent(const CGHeroInstance * h) const;
|
||||||
|
@@ -461,12 +461,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
||||||
obj->configuration.info.push_back(reward);
|
obj->configuration.info.push_back(reward);
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
|
||||||
|
|
||||||
ArtifactID artid = qap->drawRandomArtifact();
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->mission.artifacts.push_back(artid);
|
||||||
obj->quest->lastDay = -1;
|
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
|
||||||
|
|
||||||
generator.banQuestArt(artid);
|
generator.banQuestArt(artid);
|
||||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||||
@@ -513,11 +509,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
||||||
obj->configuration.info.push_back(reward);
|
obj->configuration.info.push_back(reward);
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
|
||||||
ArtifactID artid = qap->drawRandomArtifact();
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->mission.artifacts.push_back(artid);
|
||||||
obj->quest->lastDay = -1;
|
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
|
||||||
|
|
||||||
generator.banQuestArt(artid);
|
generator.banQuestArt(artid);
|
||||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||||
@@ -538,11 +531,8 @@ void TreasurePlacer::addAllPossibleObjects()
|
|||||||
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
reward.visitType = Rewardable::EEventType::EVENT_FIRST_VISIT;
|
||||||
obj->configuration.info.push_back(reward);
|
obj->configuration.info.push_back(reward);
|
||||||
|
|
||||||
obj->quest->missionType = CQuest::MISSION_ART;
|
|
||||||
ArtifactID artid = qap->drawRandomArtifact();
|
ArtifactID artid = qap->drawRandomArtifact();
|
||||||
obj->quest->addArtifactID(artid);
|
obj->quest->mission.artifacts.push_back(artid);
|
||||||
obj->quest->lastDay = -1;
|
|
||||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
|
||||||
|
|
||||||
generator.banQuestArt(artid);
|
generator.banQuestArt(artid);
|
||||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||||
|
@@ -29,20 +29,6 @@
|
|||||||
#include "PickObjectDelegate.h"
|
#include "PickObjectDelegate.h"
|
||||||
#include "../mapcontroller.h"
|
#include "../mapcontroller.h"
|
||||||
|
|
||||||
static QList<std::pair<QString, QVariant>> MissionIdentifiers
|
|
||||||
{
|
|
||||||
{QObject::tr("None"), QVariant::fromValue(int(CQuest::Emission::MISSION_NONE))},
|
|
||||||
{QObject::tr("Reach level"), QVariant::fromValue(int(CQuest::Emission::MISSION_LEVEL))},
|
|
||||||
{QObject::tr("Stats"), QVariant::fromValue(int(CQuest::Emission::MISSION_PRIMARY_STAT))},
|
|
||||||
{QObject::tr("Kill hero"), QVariant::fromValue(int(CQuest::Emission::MISSION_KILL_HERO))},
|
|
||||||
{QObject::tr("Kill monster"), QVariant::fromValue(int(CQuest::Emission::MISSION_KILL_CREATURE))},
|
|
||||||
{QObject::tr("Artifact"), QVariant::fromValue(int(CQuest::Emission::MISSION_ART))},
|
|
||||||
{QObject::tr("Army"), QVariant::fromValue(int(CQuest::Emission::MISSION_ARMY))},
|
|
||||||
{QObject::tr("Resources"), QVariant::fromValue(int(CQuest::Emission::MISSION_RESOURCES))},
|
|
||||||
{QObject::tr("Hero"), QVariant::fromValue(int(CQuest::Emission::MISSION_HERO))},
|
|
||||||
{QObject::tr("Player"), QVariant::fromValue(int(CQuest::Emission::MISSION_PLAYER))},
|
|
||||||
};
|
|
||||||
|
|
||||||
static QList<std::pair<QString, QVariant>> CharacterIdentifiers
|
static QList<std::pair<QString, QVariant>> CharacterIdentifiers
|
||||||
{
|
{
|
||||||
{QObject::tr("Compliant"), QVariant::fromValue(int(CGCreature::Character::COMPLIANT))},
|
{QObject::tr("Compliant"), QVariant::fromValue(int(CGCreature::Character::COMPLIANT))},
|
||||||
@@ -410,24 +396,28 @@ void Inspector::updateProperties(CGEvent * o)
|
|||||||
|
|
||||||
void Inspector::updateProperties(CGSeerHut * o)
|
void Inspector::updateProperties(CGSeerHut * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o || !o->quest) return;
|
||||||
|
|
||||||
{ //Mission type
|
|
||||||
auto * delegate = new InspectorDelegate;
|
|
||||||
delegate->options = MissionIdentifiers;
|
|
||||||
addProperty<CQuest::Emission>("Mission type", o->quest->missionType, delegate, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
addProperty("First visit text", o->quest->firstVisitText, new MessageDelegate, false);
|
addProperty("First visit text", o->quest->firstVisitText, new MessageDelegate, false);
|
||||||
addProperty("Next visit text", o->quest->nextVisitText, new MessageDelegate, false);
|
addProperty("Next visit text", o->quest->nextVisitText, new MessageDelegate, false);
|
||||||
addProperty("Completed text", o->quest->completedText, new MessageDelegate, false);
|
addProperty("Completed text", o->quest->completedText, new MessageDelegate, false);
|
||||||
|
addProperty("Repeat quest", o->quest->repeatedQuest, false);
|
||||||
|
addProperty("Time limit", o->quest->lastDay, false);
|
||||||
|
|
||||||
{ //Quest
|
{ //Quest
|
||||||
auto * delegate = new QuestDelegate(*controller.map(), *o);
|
auto * delegate = new QuestDelegate(controller, *o->quest);
|
||||||
addProperty("Quest", PropertyEditorPlaceholder(), delegate, false);
|
addProperty("Quest", PropertyEditorPlaceholder(), delegate, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Inspector::updateProperties(CGQuestGuard * o)
|
||||||
|
{
|
||||||
|
if(!o || !o->quest) return;
|
||||||
|
|
||||||
|
addProperty("Reward", PropertyEditorPlaceholder(), nullptr, true);
|
||||||
|
addProperty("Repeat quest", o->quest->repeatedQuest, true);
|
||||||
|
}
|
||||||
|
|
||||||
void Inspector::updateProperties()
|
void Inspector::updateProperties()
|
||||||
{
|
{
|
||||||
if(!obj)
|
if(!obj)
|
||||||
@@ -470,6 +460,7 @@ void Inspector::updateProperties()
|
|||||||
UPDATE_OBJ_PROPERTIES(CGPandoraBox);
|
UPDATE_OBJ_PROPERTIES(CGPandoraBox);
|
||||||
UPDATE_OBJ_PROPERTIES(CGEvent);
|
UPDATE_OBJ_PROPERTIES(CGEvent);
|
||||||
UPDATE_OBJ_PROPERTIES(CGSeerHut);
|
UPDATE_OBJ_PROPERTIES(CGSeerHut);
|
||||||
|
UPDATE_OBJ_PROPERTIES(CGQuestGuard);
|
||||||
|
|
||||||
table->show();
|
table->show();
|
||||||
}
|
}
|
||||||
@@ -516,6 +507,7 @@ void Inspector::setProperty(const QString & key, const QVariant & value)
|
|||||||
SET_PROPERTIES(CGPandoraBox);
|
SET_PROPERTIES(CGPandoraBox);
|
||||||
SET_PROPERTIES(CGEvent);
|
SET_PROPERTIES(CGEvent);
|
||||||
SET_PROPERTIES(CGSeerHut);
|
SET_PROPERTIES(CGSeerHut);
|
||||||
|
SET_PROPERTIES(CGQuestGuard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inspector::setProperty(CArmedInstance * o, const QString & key, const QVariant & value)
|
void Inspector::setProperty(CArmedInstance * o, const QString & key, const QVariant & value)
|
||||||
@@ -538,7 +530,8 @@ void Inspector::setProperty(CGPandoraBox * o, const QString & key, const QVarian
|
|||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Message")
|
if(key == "Message")
|
||||||
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
|
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inspector::setProperty(CGEvent * o, const QString & key, const QVariant & value)
|
void Inspector::setProperty(CGEvent * o, const QString & key, const QVariant & value)
|
||||||
@@ -560,7 +553,8 @@ void Inspector::setProperty(CGTownInstance * o, const QString & key, const QVari
|
|||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Town name")
|
if(key == "Town name")
|
||||||
o->setNameTextId(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("town", o->instanceName, "name"), value.toString().toStdString()));
|
o->setNameTextId(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("town", o->instanceName, "name"), value.toString().toStdString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inspector::setProperty(CGSignBottle * o, const QString & key, const QVariant & value)
|
void Inspector::setProperty(CGSignBottle * o, const QString & key, const QVariant & value)
|
||||||
@@ -568,7 +562,8 @@ void Inspector::setProperty(CGSignBottle * o, const QString & key, const QVarian
|
|||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Message")
|
if(key == "Message")
|
||||||
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("sign", o->instanceName, "message"), value.toString().toStdString()));
|
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("sign", o->instanceName, "message"), value.toString().toStdString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inspector::setProperty(CGMine * o, const QString & key, const QVariant & value)
|
void Inspector::setProperty(CGMine * o, const QString & key, const QVariant & value)
|
||||||
@@ -584,7 +579,8 @@ void Inspector::setProperty(CGArtifact * o, const QString & key, const QVariant
|
|||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Message")
|
if(key == "Message")
|
||||||
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
|
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("guards", o->instanceName, "message"), value.toString().toStdString()));
|
||||||
|
|
||||||
if(o->storedArtifact && key == "Spell")
|
if(o->storedArtifact && key == "Spell")
|
||||||
{
|
{
|
||||||
@@ -623,10 +619,12 @@ void Inspector::setProperty(CGHeroInstance * o, const QString & key, const QVari
|
|||||||
o->gender = EHeroGender(value.toInt());
|
o->gender = EHeroGender(value.toInt());
|
||||||
|
|
||||||
if(key == "Name")
|
if(key == "Name")
|
||||||
o->nameCustomTextId = mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("hero", o->instanceName, "name"), value.toString().toStdString());
|
o->nameCustomTextId = mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("hero", o->instanceName, "name"), value.toString().toStdString());
|
||||||
|
|
||||||
if(key == "Biography")
|
if(key == "Biography")
|
||||||
o->biographyCustomTextId = mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("hero", o->instanceName, "biography"), value.toString().toStdString());
|
o->biographyCustomTextId = mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("hero", o->instanceName, "biography"), value.toString().toStdString());
|
||||||
|
|
||||||
if(key == "Experience")
|
if(key == "Experience")
|
||||||
o->exp = value.toString().toInt();
|
o->exp = value.toString().toInt();
|
||||||
@@ -662,7 +660,8 @@ void Inspector::setProperty(CGCreature * o, const QString & key, const QVariant
|
|||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Message")
|
if(key == "Message")
|
||||||
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("monster", o->instanceName, "message"), value.toString().toStdString()));
|
o->message = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("monster", o->instanceName, "message"), value.toString().toStdString()));
|
||||||
if(key == "Character")
|
if(key == "Character")
|
||||||
o->character = CGCreature::Character(value.toInt());
|
o->character = CGCreature::Character(value.toInt());
|
||||||
if(key == "Never flees")
|
if(key == "Never flees")
|
||||||
@@ -677,14 +676,24 @@ void Inspector::setProperty(CGSeerHut * o, const QString & key, const QVariant &
|
|||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
if(key == "Mission type")
|
|
||||||
o->quest->missionType = CQuest::Emission(value.toInt());
|
|
||||||
if(key == "First visit text")
|
if(key == "First visit text")
|
||||||
o->quest->firstVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("quest", o->instanceName, "firstVisit"), value.toString().toStdString()));
|
o->quest->firstVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("quest", o->instanceName, "firstVisit"), value.toString().toStdString()));
|
||||||
if(key == "Next visit text")
|
if(key == "Next visit text")
|
||||||
o->quest->nextVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("quest", o->instanceName, "nextVisit"), value.toString().toStdString()));
|
o->quest->nextVisitText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("quest", o->instanceName, "nextVisit"), value.toString().toStdString()));
|
||||||
if(key == "Completed text")
|
if(key == "Completed text")
|
||||||
o->quest->completedText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(), TextIdentifier("quest", o->instanceName, "completed"), value.toString().toStdString()));
|
o->quest->completedText = MetaString::createFromTextID(mapRegisterLocalizedString("map", *controller.map(),
|
||||||
|
TextIdentifier("quest", o->instanceName, "completed"), value.toString().toStdString()));
|
||||||
|
if(key == "Repeat quest")
|
||||||
|
o->quest->repeatedQuest = value.toBool();
|
||||||
|
if(key == "Time limit")
|
||||||
|
o->quest->lastDay = value.toString().toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::setProperty(CGQuestGuard * o, const QString & key, const QVariant & value)
|
||||||
|
{
|
||||||
|
if(!o) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -797,24 +806,6 @@ QTableWidgetItem * Inspector::addProperty(CGCreature::Character value)
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTableWidgetItem * Inspector::addProperty(CQuest::Emission value)
|
|
||||||
{
|
|
||||||
auto * item = new QTableWidgetItem;
|
|
||||||
item->setFlags(Qt::NoItemFlags);
|
|
||||||
item->setData(Qt::UserRole, QVariant::fromValue(int(value)));
|
|
||||||
|
|
||||||
for(auto & i : MissionIdentifiers)
|
|
||||||
{
|
|
||||||
if(i.second.toInt() == value)
|
|
||||||
{
|
|
||||||
item->setText(i.first);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
Inspector::Inspector(MapController & c, CGObjectInstance * o, QTableWidget * t): obj(o), table(t), controller(c)
|
Inspector::Inspector(MapController & c, CGObjectInstance * o, QTableWidget * t): obj(o), table(t), controller(c)
|
||||||
|
@@ -82,6 +82,7 @@ protected:
|
|||||||
DECLARE_OBJ_PROPERTY_METHODS(CGPandoraBox);
|
DECLARE_OBJ_PROPERTY_METHODS(CGPandoraBox);
|
||||||
DECLARE_OBJ_PROPERTY_METHODS(CGEvent);
|
DECLARE_OBJ_PROPERTY_METHODS(CGEvent);
|
||||||
DECLARE_OBJ_PROPERTY_METHODS(CGSeerHut);
|
DECLARE_OBJ_PROPERTY_METHODS(CGSeerHut);
|
||||||
|
DECLARE_OBJ_PROPERTY_METHODS(CGQuestGuard);
|
||||||
|
|
||||||
//===============DECLARE PROPERTY VALUE TYPE==============================
|
//===============DECLARE PROPERTY VALUE TYPE==============================
|
||||||
QTableWidgetItem * addProperty(unsigned int value);
|
QTableWidgetItem * addProperty(unsigned int value);
|
||||||
@@ -96,7 +97,6 @@ protected:
|
|||||||
QTableWidgetItem * addProperty(bool value);
|
QTableWidgetItem * addProperty(bool value);
|
||||||
QTableWidgetItem * addProperty(CGObjectInstance * value);
|
QTableWidgetItem * addProperty(CGObjectInstance * value);
|
||||||
QTableWidgetItem * addProperty(CGCreature::Character value);
|
QTableWidgetItem * addProperty(CGCreature::Character value);
|
||||||
QTableWidgetItem * addProperty(CQuest::Emission value);
|
|
||||||
QTableWidgetItem * addProperty(PropertyEditorPlaceholder value);
|
QTableWidgetItem * addProperty(PropertyEditorPlaceholder value);
|
||||||
|
|
||||||
//===============END OF DECLARATION=======================================
|
//===============END OF DECLARATION=======================================
|
||||||
|
@@ -10,21 +10,124 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "questwidget.h"
|
#include "questwidget.h"
|
||||||
#include "ui_questwidget.h"
|
#include "ui_questwidget.h"
|
||||||
|
#include "../mapcontroller.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "../lib/CSkillHandler.h"
|
#include "../lib/CSkillHandler.h"
|
||||||
|
#include "../lib/spells/CSpellHandler.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CCreatureHandler.h"
|
#include "../lib/CCreatureHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/constants/StringConstants.h"
|
#include "../lib/constants/StringConstants.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
|
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../lib/mapObjects/CGCreature.h"
|
||||||
|
|
||||||
QuestWidget::QuestWidget(const CMap & _map, CGSeerHut & _sh, QWidget *parent) :
|
QuestWidget::QuestWidget(MapController & _controller, CQuest & _sh, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
map(_map),
|
controller(_controller),
|
||||||
seerhut(_sh),
|
quest(_sh),
|
||||||
ui(new Ui::QuestWidget)
|
ui(new Ui::QuestWidget)
|
||||||
{
|
{
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->lDayOfWeek->addItem(tr("None"));
|
||||||
|
for(int i = 1; i <= 7; ++i)
|
||||||
|
ui->lDayOfWeek->addItem(tr("Day %1").arg(i));
|
||||||
|
|
||||||
|
//fill resources
|
||||||
|
ui->lResources->setRowCount(GameConstants::RESOURCE_QUANTITY - 1);
|
||||||
|
for(int i = 0; i < GameConstants::RESOURCE_QUANTITY - 1; ++i)
|
||||||
|
{
|
||||||
|
auto * item = new QTableWidgetItem(QString::fromStdString(GameConstants::RESOURCE_NAMES[i]));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||||
|
ui->lResources->setItem(i, 0, item);
|
||||||
|
auto * spinBox = new QSpinBox;
|
||||||
|
spinBox->setMaximum(i == GameResID::GOLD ? 999999 : 999);
|
||||||
|
ui->lResources->setCellWidget(i, 1, spinBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill artifacts
|
||||||
|
for(int i = 0; i < controller.map()->allowedArtifact.size(); ++i)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(VLC->artifacts()->getByIndex(i)->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
if(!controller.map()->allowedArtifact[i])
|
||||||
|
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
|
||||||
|
ui->lArtifacts->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill spells
|
||||||
|
for(int i = 0; i < controller.map()->allowedSpells.size(); ++i)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(VLC->spells()->getByIndex(i)->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
if(!controller.map()->allowedSpells[i])
|
||||||
|
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
|
||||||
|
ui->lSpells->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill skills
|
||||||
|
ui->lSkills->setRowCount(controller.map()->allowedAbilities.size());
|
||||||
|
for(int i = 0; i < controller.map()->allowedAbilities.size(); ++i)
|
||||||
|
{
|
||||||
|
auto * item = new QTableWidgetItem(QString::fromStdString(VLC->skills()->getByIndex(i)->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||||
|
|
||||||
|
auto * widget = new QComboBox;
|
||||||
|
for(auto & s : NSecondarySkill::levels)
|
||||||
|
widget->addItem(QString::fromStdString(s));
|
||||||
|
|
||||||
|
if(!controller.map()->allowedAbilities[i])
|
||||||
|
{
|
||||||
|
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
|
||||||
|
widget->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->lSkills->setItem(i, 0, item);
|
||||||
|
ui->lSkills->setCellWidget(i, 1, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill creatures
|
||||||
|
for(auto & creature : VLC->creh->objects)
|
||||||
|
{
|
||||||
|
ui->lCreatureId->addItem(QString::fromStdString(creature->getNameSingularTranslated()));
|
||||||
|
ui->lCreatureId->setItemData(ui->lCreatureId->count() - 1, creature->getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill heroes
|
||||||
|
VLC->heroTypes()->forEach([this](const HeroType * hero, bool &)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(hero->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(hero->getId().getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lHeroes->addItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
//fill hero classes
|
||||||
|
VLC->heroClasses()->forEach([this](const HeroClass * heroClass, bool &)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(heroClass->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(heroClass->getId().getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lHeroClasses->addItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
//fill players
|
||||||
|
for(auto color = PlayerColor(0); color < PlayerColor::PLAYER_LIMIT; ++color)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[color.getNum()]));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(color.getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lPlayers->addItem(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QuestWidget::~QuestWidget()
|
QuestWidget::~QuestWidget()
|
||||||
@@ -34,137 +137,259 @@ QuestWidget::~QuestWidget()
|
|||||||
|
|
||||||
void QuestWidget::obtainData()
|
void QuestWidget::obtainData()
|
||||||
{
|
{
|
||||||
assert(seerhut.quest);
|
ui->lDayOfWeek->setCurrentIndex(quest.mission.dayOfWeek);
|
||||||
bool activeId = false;
|
ui->lDaysPassed->setValue(quest.mission.daysPassed);
|
||||||
bool activeAmount = false;
|
ui->lHeroLevel->setValue(quest.mission.heroLevel);
|
||||||
switch(seerhut.quest->missionType) {
|
ui->lHeroExperience->setValue(quest.mission.heroExperience);
|
||||||
case CQuest::Emission::MISSION_LEVEL:
|
ui->lManaPoints->setValue(quest.mission.manaPoints);
|
||||||
activeAmount = true;
|
ui->lManaPercentage->setValue(quest.mission.manaPercentage);
|
||||||
ui->targetId->addItem("Reach level");
|
ui->lAttack->setValue(quest.mission.primary[0]);
|
||||||
ui->targetAmount->setText(QString::number(seerhut.quest->m13489val));
|
ui->lDefence->setValue(quest.mission.primary[1]);
|
||||||
break;
|
ui->lPower->setValue(quest.mission.primary[2]);
|
||||||
case CQuest::Emission::MISSION_PRIMARY_STAT:
|
ui->lKnowledge->setValue(quest.mission.primary[3]);
|
||||||
activeId = true;
|
for(int i = 0; i < ui->lResources->rowCount(); ++i)
|
||||||
activeAmount = true;
|
{
|
||||||
for(auto s : NPrimarySkill::names)
|
if(auto * widget = qobject_cast<QSpinBox*>(ui->lResources->cellWidget(i, 1)))
|
||||||
ui->targetId->addItem(QString::fromStdString(s));
|
widget->setValue(quest.mission.resources[i]);
|
||||||
for(int i = 0; i < seerhut.quest->m2stats.size(); ++i)
|
|
||||||
{
|
|
||||||
if(seerhut.quest->m2stats[i] > 0)
|
|
||||||
{
|
|
||||||
ui->targetId->setCurrentIndex(i);
|
|
||||||
ui->targetAmount->setText(QString::number(seerhut.quest->m2stats[i]));
|
|
||||||
break; //TODO: support multiple stats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_KILL_HERO:
|
|
||||||
activeId = true;
|
|
||||||
//TODO: implement
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_KILL_CREATURE:
|
|
||||||
activeId = true;
|
|
||||||
//TODO: implement
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_ART:
|
|
||||||
activeId = true;
|
|
||||||
for(int i = 0; i < map.allowedArtifact.size(); ++i)
|
|
||||||
ui->targetId->addItem(QString::fromStdString(VLC->arth->objects.at(i)->getNameTranslated()));
|
|
||||||
if(!seerhut.quest->m5arts.empty())
|
|
||||||
ui->targetId->setCurrentIndex(seerhut.quest->m5arts.front());
|
|
||||||
//TODO: support multiple artifacts
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_ARMY:
|
|
||||||
activeId = true;
|
|
||||||
activeAmount = true;
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_RESOURCES:
|
|
||||||
activeId = true;
|
|
||||||
activeAmount = true;
|
|
||||||
for(auto s : GameConstants::RESOURCE_NAMES)
|
|
||||||
ui->targetId->addItem(QString::fromStdString(s));
|
|
||||||
for(int i = 0; i < seerhut.quest->m7resources.size(); ++i)
|
|
||||||
{
|
|
||||||
if(seerhut.quest->m7resources[i] > 0)
|
|
||||||
{
|
|
||||||
ui->targetId->setCurrentIndex(i);
|
|
||||||
ui->targetAmount->setText(QString::number(seerhut.quest->m7resources[i]));
|
|
||||||
break; //TODO: support multiple resources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_HERO:
|
|
||||||
activeId = true;
|
|
||||||
for(int i = 0; i < map.allowedHeroes.size(); ++i)
|
|
||||||
ui->targetId->addItem(QString::fromStdString(VLC->heroh->objects.at(i)->getNameTranslated()));
|
|
||||||
ui->targetId->setCurrentIndex(seerhut.quest->m13489val);
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_PLAYER:
|
|
||||||
activeId = true;
|
|
||||||
for(auto s : GameConstants::PLAYER_COLOR_NAMES)
|
|
||||||
ui->targetId->addItem(QString::fromStdString(s));
|
|
||||||
ui->targetId->setCurrentIndex(seerhut.quest->m13489val);
|
|
||||||
break;
|
|
||||||
case CQuest::Emission::MISSION_KEYMASTER:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->targetId->setEnabled(activeId);
|
for(auto i : quest.mission.artifacts)
|
||||||
ui->targetAmount->setEnabled(activeAmount);
|
ui->lArtifacts->item(VLC->artifacts()->getById(i)->getIndex())->setCheckState(Qt::Checked);
|
||||||
|
for(auto i : quest.mission.spells)
|
||||||
|
ui->lArtifacts->item(VLC->spells()->getById(i)->getIndex())->setCheckState(Qt::Checked);
|
||||||
|
for(auto & i : quest.mission.secondary)
|
||||||
|
{
|
||||||
|
int index = VLC->skills()->getById(i.first)->getIndex();
|
||||||
|
if(auto * widget = qobject_cast<QComboBox*>(ui->lSkills->cellWidget(index, 1)))
|
||||||
|
widget->setCurrentIndex(i.second);
|
||||||
|
}
|
||||||
|
for(auto & i : quest.mission.creatures)
|
||||||
|
{
|
||||||
|
int index = i.type->getIndex();
|
||||||
|
ui->lCreatureId->setCurrentIndex(index);
|
||||||
|
ui->lCreatureAmount->setValue(i.count);
|
||||||
|
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
||||||
|
}
|
||||||
|
for(auto & i : quest.mission.heroes)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lHeroes->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lHeroes->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lHeroes->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto & i : quest.mission.heroClasses)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lHeroClasses->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lHeroClasses->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lHeroClasses->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto & i : quest.mission.players)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lPlayers->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lPlayers->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lPlayers->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(quest.killTarget != ObjectInstanceID::NONE && quest.killTarget < controller.map()->objects.size())
|
||||||
|
ui->lKillTarget->setText(QString::fromStdString(controller.map()->objects[quest.killTarget]->instanceName));
|
||||||
|
else
|
||||||
|
quest.killTarget = ObjectInstanceID::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QuestWidget::commitChanges()
|
bool QuestWidget::commitChanges()
|
||||||
{
|
{
|
||||||
assert(seerhut.quest);
|
quest.mission.dayOfWeek = ui->lDayOfWeek->currentIndex();
|
||||||
switch(seerhut.quest->missionType) {
|
quest.mission.daysPassed = ui->lDaysPassed->value();
|
||||||
case CQuest::Emission::MISSION_LEVEL:
|
quest.mission.heroLevel = ui->lHeroLevel->value();
|
||||||
seerhut.quest->m13489val = ui->targetAmount->text().toInt();
|
quest.mission.heroExperience = ui->lHeroExperience->value();
|
||||||
return QString("Reach lvl ").append(ui->targetAmount->text());
|
quest.mission.manaPoints = ui->lManaPoints->value();
|
||||||
case CQuest::Emission::MISSION_PRIMARY_STAT:
|
quest.mission.manaPercentage = ui->lManaPercentage->value();
|
||||||
seerhut.quest->m2stats.resize(sizeof(NPrimarySkill::names), 0);
|
quest.mission.primary[0] = ui->lAttack->value();
|
||||||
seerhut.quest->m2stats[ui->targetId->currentIndex()] = ui->targetAmount->text().toInt();
|
quest.mission.primary[1] = ui->lDefence->value();
|
||||||
//TODO: support multiple stats
|
quest.mission.primary[2] = ui->lPower->value();
|
||||||
return ui->targetId->currentText().append(ui->targetAmount->text());
|
quest.mission.primary[3] = ui->lKnowledge->value();
|
||||||
case CQuest::Emission::MISSION_KILL_HERO:
|
for(int i = 0; i < ui->lResources->rowCount(); ++i)
|
||||||
//TODO: implement
|
{
|
||||||
return QString("N/A");
|
if(auto * widget = qobject_cast<QSpinBox*>(ui->lResources->cellWidget(i, 1)))
|
||||||
case CQuest::Emission::MISSION_KILL_CREATURE:
|
quest.mission.resources[i] = widget->value();
|
||||||
//TODO: implement
|
|
||||||
return QString("N/A");
|
|
||||||
case CQuest::Emission::MISSION_ART:
|
|
||||||
seerhut.quest->m5arts.clear();
|
|
||||||
seerhut.quest->m5arts.push_back(ArtifactID(ui->targetId->currentIndex()));
|
|
||||||
//TODO: support multiple artifacts
|
|
||||||
return ui->targetId->currentText();
|
|
||||||
case CQuest::Emission::MISSION_ARMY:
|
|
||||||
//TODO: implement
|
|
||||||
return QString("N/A");
|
|
||||||
case CQuest::Emission::MISSION_RESOURCES:
|
|
||||||
seerhut.quest->m7resources[ui->targetId->currentIndex()] = ui->targetAmount->text().toInt();
|
|
||||||
//TODO: support resources
|
|
||||||
return ui->targetId->currentText().append(ui->targetAmount->text());
|
|
||||||
case CQuest::Emission::MISSION_HERO:
|
|
||||||
seerhut.quest->m13489val = ui->targetId->currentIndex();
|
|
||||||
return ui->targetId->currentText();
|
|
||||||
case CQuest::Emission::MISSION_PLAYER:
|
|
||||||
seerhut.quest->m13489val = ui->targetId->currentIndex();
|
|
||||||
return ui->targetId->currentText();
|
|
||||||
case CQuest::Emission::MISSION_KEYMASTER:
|
|
||||||
return QString("N/A");
|
|
||||||
default:
|
|
||||||
return QString("N/A");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quest.mission.artifacts.clear();
|
||||||
|
for(int i = 0; i < ui->lArtifacts->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lArtifacts->item(i)->checkState() == Qt::Checked)
|
||||||
|
quest.mission.artifacts.push_back(VLC->artifacts()->getByIndex(i)->getId());
|
||||||
|
}
|
||||||
|
quest.mission.spells.clear();
|
||||||
|
for(int i = 0; i < ui->lSpells->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lSpells->item(i)->checkState() == Qt::Checked)
|
||||||
|
quest.mission.spells.push_back(VLC->spells()->getByIndex(i)->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
quest.mission.secondary.clear();
|
||||||
|
for(int i = 0; i < ui->lSkills->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if(auto * widget = qobject_cast<QComboBox*>(ui->lSkills->cellWidget(i, 1)))
|
||||||
|
{
|
||||||
|
if(widget->currentIndex() > 0)
|
||||||
|
quest.mission.secondary[VLC->skills()->getByIndex(i)->getId()] = widget->currentIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quest.mission.creatures.clear();
|
||||||
|
for(int i = 0; i < ui->lCreatures->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
int index = ui->lCreatures->item(i, 0)->data(Qt::UserRole).toInt();
|
||||||
|
if(auto * widget = qobject_cast<QSpinBox*>(ui->lCreatures->cellWidget(i, 1)))
|
||||||
|
if(widget->value())
|
||||||
|
quest.mission.creatures.emplace_back(VLC->creatures()->getByIndex(index)->getId(), widget->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
quest.mission.heroes.clear();
|
||||||
|
for(int i = 0; i < ui->lHeroes->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lHeroes->item(i)->checkState() == Qt::Checked)
|
||||||
|
quest.mission.heroes.emplace_back(ui->lHeroes->item(i)->data(Qt::UserRole).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
quest.mission.heroClasses.clear();
|
||||||
|
for(int i = 0; i < ui->lHeroClasses->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lHeroClasses->item(i)->checkState() == Qt::Checked)
|
||||||
|
quest.mission.heroClasses.emplace_back(ui->lHeroClasses->item(i)->data(Qt::UserRole).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
quest.mission.players.clear();
|
||||||
|
for(int i = 0; i < ui->lPlayers->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lPlayers->item(i)->checkState() == Qt::Checked)
|
||||||
|
quest.mission.players.emplace_back(ui->lPlayers->item(i)->data(Qt::UserRole).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
//quest.killTarget is set directly in object picking
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuestDelegate::QuestDelegate(const CMap & m, CGSeerHut & t): map(m), seerhut(t), QStyledItemDelegate()
|
void QuestWidget::onCreatureAdd(QTableWidget * listWidget, QComboBox * comboWidget, QSpinBox * spinWidget)
|
||||||
|
{
|
||||||
|
QTableWidgetItem * item = nullptr;
|
||||||
|
QSpinBox * widget = nullptr;
|
||||||
|
for(int i = 0; i < listWidget->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if(auto * cname = listWidget->item(i, 0))
|
||||||
|
{
|
||||||
|
if(cname->data(Qt::UserRole).toInt() == comboWidget->currentData().toInt())
|
||||||
|
{
|
||||||
|
item = cname;
|
||||||
|
widget = qobject_cast<QSpinBox*>(listWidget->cellWidget(i, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!item)
|
||||||
|
{
|
||||||
|
listWidget->setRowCount(listWidget->rowCount() + 1);
|
||||||
|
item = new QTableWidgetItem(comboWidget->currentText());
|
||||||
|
listWidget->setItem(listWidget->rowCount() - 1, 0, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setData(Qt::UserRole, comboWidget->currentData());
|
||||||
|
|
||||||
|
if(!widget)
|
||||||
|
{
|
||||||
|
widget = new QSpinBox;
|
||||||
|
widget->setRange(spinWidget->minimum(), spinWidget->maximum());
|
||||||
|
listWidget->setCellWidget(listWidget->rowCount() - 1, 1, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget->setValue(spinWidget->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestWidget::on_lKillTargetSelect_clicked()
|
||||||
|
{
|
||||||
|
auto pred = [](const CGObjectInstance * obj) -> bool
|
||||||
|
{
|
||||||
|
if(auto * o = dynamic_cast<const CGHeroInstance*>(obj))
|
||||||
|
return o->ID != Obj::PRISON;
|
||||||
|
if(dynamic_cast<const CGCreature*>(obj))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int lvl : {0, 1})
|
||||||
|
{
|
||||||
|
auto & l = controller.scene(lvl)->objectPickerView;
|
||||||
|
l.highlight(pred);
|
||||||
|
l.update();
|
||||||
|
QObject::connect(&l, &ObjectPickerLayer::selectionMade, this, &QuestWidget::onTargetPicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestWidget::onTargetPicked(const CGObjectInstance * obj)
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
|
||||||
|
for(int lvl : {0, 1})
|
||||||
|
{
|
||||||
|
auto & l = controller.scene(lvl)->objectPickerView;
|
||||||
|
l.clear();
|
||||||
|
l.update();
|
||||||
|
QObject::disconnect(&l, &ObjectPickerLayer::selectionMade, this, &QuestWidget::onTargetPicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!obj) //discarded
|
||||||
|
{
|
||||||
|
quest.killTarget = ObjectInstanceID::NONE;
|
||||||
|
ui->lKillTarget->setText("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->lKillTarget->setText(QString::fromStdString(obj->instanceName));
|
||||||
|
quest.killTarget = obj->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestWidget::on_lCreatureAdd_clicked()
|
||||||
|
{
|
||||||
|
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QuestWidget::on_lCreatureRemove_clicked()
|
||||||
|
{
|
||||||
|
std::set<int, std::greater<int>> rowsToRemove;
|
||||||
|
for(auto * i : ui->lCreatures->selectedItems())
|
||||||
|
rowsToRemove.insert(i->row());
|
||||||
|
|
||||||
|
for(auto i : rowsToRemove)
|
||||||
|
ui->lCreatures->removeRow(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
QuestDelegate::QuestDelegate(MapController & c, CQuest & t): controller(c), quest(t), QStyledItemDelegate()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget * QuestDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
QWidget * QuestDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||||
{
|
{
|
||||||
return new QuestWidget(map, seerhut, parent);
|
return new QuestWidget(controller, quest, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuestDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
|
void QuestDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
|
||||||
@@ -183,11 +408,26 @@ void QuestDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, c
|
|||||||
{
|
{
|
||||||
if(auto *ed = qobject_cast<QuestWidget *>(editor))
|
if(auto *ed = qobject_cast<QuestWidget *>(editor))
|
||||||
{
|
{
|
||||||
auto quest = ed->commitChanges();
|
ed->commitChanges();
|
||||||
model->setData(index, quest);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QStyledItemDelegate::setModelData(editor, model, index);
|
QStyledItemDelegate::setModelData(editor, model, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QuestDelegate::eventFilter(QObject * object, QEvent * event)
|
||||||
|
{
|
||||||
|
if(auto * ed = qobject_cast<QuestWidget *>(object))
|
||||||
|
{
|
||||||
|
if(event->type() == QEvent::Hide || event->type() == QEvent::FocusOut)
|
||||||
|
return false;
|
||||||
|
if(event->type() == QEvent::Close)
|
||||||
|
{
|
||||||
|
emit commitData(ed);
|
||||||
|
emit closeEditor(ed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QStyledItemDelegate::eventFilter(object, event);
|
||||||
|
}
|
||||||
|
@@ -16,20 +16,33 @@ namespace Ui {
|
|||||||
class QuestWidget;
|
class QuestWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MapController;
|
||||||
|
|
||||||
class QuestWidget : public QDialog
|
class QuestWidget : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit QuestWidget(const CMap &, CGSeerHut &, QWidget *parent = nullptr);
|
explicit QuestWidget(MapController &, CQuest &, QWidget *parent = nullptr);
|
||||||
~QuestWidget();
|
~QuestWidget();
|
||||||
|
|
||||||
void obtainData();
|
void obtainData();
|
||||||
QString commitChanges();
|
bool commitChanges();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTargetPicked(const CGObjectInstance *);
|
||||||
|
|
||||||
|
void on_lKillTargetSelect_clicked();
|
||||||
|
|
||||||
|
void on_lCreatureAdd_clicked();
|
||||||
|
|
||||||
|
void on_lCreatureRemove_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CGSeerHut & seerhut;
|
void onCreatureAdd(QTableWidget * listWidget, QComboBox * comboWidget, QSpinBox * spinWidget);
|
||||||
const CMap & map;
|
|
||||||
|
CQuest & quest;
|
||||||
|
MapController & controller;
|
||||||
Ui::QuestWidget *ui;
|
Ui::QuestWidget *ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,13 +52,16 @@ class QuestDelegate : public QStyledItemDelegate
|
|||||||
public:
|
public:
|
||||||
using QStyledItemDelegate::QStyledItemDelegate;
|
using QStyledItemDelegate::QStyledItemDelegate;
|
||||||
|
|
||||||
QuestDelegate(const CMap &, CGSeerHut &);
|
QuestDelegate(MapController &, CQuest &);
|
||||||
|
|
||||||
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
|
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
|
||||||
void setEditorData(QWidget * editor, const QModelIndex & index) const override;
|
void setEditorData(QWidget * editor, const QModelIndex & index) const override;
|
||||||
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
|
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject * object, QEvent * event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CGSeerHut & seerhut;
|
CQuest & quest;
|
||||||
const CMap & map;
|
MapController & controller;
|
||||||
};
|
};
|
||||||
|
@@ -9,8 +9,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>429</width>
|
<width>531</width>
|
||||||
<height>89</height>
|
<height>495</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -19,34 +19,616 @@
|
|||||||
<property name="modal">
|
<property name="modal">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="targetId">
|
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||||
<property name="sizePolicy">
|
<item>
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
<widget class="QLabel" name="label_7">
|
||||||
<horstretch>0</horstretch>
|
<property name="text">
|
||||||
<verstretch>0</verstretch>
|
<string>Day of week</string>
|
||||||
</sizepolicy>
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="lDayOfWeek">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>120</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Days passed</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lDaysPassed">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hero level</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lHeroLevel">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hero experience</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lHeroExperience">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100000</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Spell points</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lManaPoints">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>999</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lManaPercentage">
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Kill hero/monster</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lKillTarget">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="lKillTargetSelect">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Primary skills</string>
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Attack</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lAttack"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Defence</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lDefence"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>Spell power</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lPower"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>Knowledge</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lKnowledge"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="targetAmount">
|
<widget class="QTabWidget" name="tabWidget_2">
|
||||||
<property name="sizePolicy">
|
<property name="layoutDirection">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<enum>Qt::LeftToRight</enum>
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="tabPosition">
|
||||||
<size>
|
<enum>QTabWidget::North</enum>
|
||||||
<width>60</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="inputMethodHints">
|
<property name="tabShape">
|
||||||
<set>Qt::ImhDigitsOnly</set>
|
<enum>QTabWidget::Rounded</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="elideMode">
|
||||||
|
<enum>Qt::ElideNone</enum>
|
||||||
|
</property>
|
||||||
|
<property name="usesScrollButtons">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="documentMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabBarAutoHide">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab_3">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Resources</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="lResources">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||||
|
<number>180</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
|
<number>24</number>
|
||||||
|
</attribute>
|
||||||
|
<column/>
|
||||||
|
<column/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_4">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Artifacts</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lArtifacts">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_5">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Spells</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lSpells">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_7">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Skills</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="lSkills">
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||||
|
<number>180</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
|
<number>24</number>
|
||||||
|
</attribute>
|
||||||
|
<column/>
|
||||||
|
<column/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_6">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Creatures</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="lCreatureId">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="lCreatureAmount">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>60</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>9999</number>
|
||||||
|
</property>
|
||||||
|
<property name="stepType">
|
||||||
|
<enum>QAbstractSpinBox::AdaptiveDecimalStepType</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="lCreatureAdd">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="lCreatureRemove">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="lCreatures">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::MultiSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="columnCount">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="horizontalHeaderDefaultSectionSize">
|
||||||
|
<number>180</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
|
<number>24</number>
|
||||||
|
</attribute>
|
||||||
|
<column/>
|
||||||
|
<column/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Heroes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lHeroes">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Hero classes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lHeroClasses">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_8">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Players</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lPlayers">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "../lib/CSkillHandler.h"
|
#include "../lib/CSkillHandler.h"
|
||||||
#include "../lib/spells/CSpellHandler.h"
|
#include "../lib/spells/CSpellHandler.h"
|
||||||
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CCreatureHandler.h"
|
#include "../lib/CCreatureHandler.h"
|
||||||
#include "../lib/constants/StringConstants.h"
|
#include "../lib/constants/StringConstants.h"
|
||||||
@@ -55,7 +56,11 @@ RewardsWidget::RewardsWidget(CMap & m, CRewardableObject & p, QWidget *parent) :
|
|||||||
auto * item = new QTableWidgetItem(QString::fromStdString(GameConstants::RESOURCE_NAMES[i]));
|
auto * item = new QTableWidgetItem(QString::fromStdString(GameConstants::RESOURCE_NAMES[i]));
|
||||||
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||||
w->setItem(i, 0, item);
|
w->setItem(i, 0, item);
|
||||||
w->setCellWidget(i, 1, new QSpinBox);
|
auto * spinBox = new QSpinBox;
|
||||||
|
spinBox->setMaximum(i == GameResID::GOLD ? 999999 : 999);
|
||||||
|
if(w == ui->rResources)
|
||||||
|
spinBox->setMinimum(i == GameResID::GOLD ? -999999 : -999);
|
||||||
|
w->setCellWidget(i, 1, spinBox);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +136,36 @@ RewardsWidget::RewardsWidget(CMap & m, CRewardableObject & p, QWidget *parent) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fill heroes
|
||||||
|
VLC->heroTypes()->forEach([this](const HeroType * hero, bool &)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(hero->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(hero->getId().getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lHeroes->addItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
//fill hero classes
|
||||||
|
VLC->heroClasses()->forEach([this](const HeroClass * heroClass, bool &)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(heroClass->getNameTranslated()));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(heroClass->getId().getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lHeroClasses->addItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
//fill players
|
||||||
|
for(auto color = PlayerColor(0); color < PlayerColor::PLAYER_LIMIT; ++color)
|
||||||
|
{
|
||||||
|
auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[color.getNum()]));
|
||||||
|
item->setData(Qt::UserRole, QVariant::fromValue(color.getNum()));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
ui->lPlayers->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
//fill spell cast
|
//fill spell cast
|
||||||
for(auto & s : NSecondarySkill::levels)
|
for(auto & s : NSecondarySkill::levels)
|
||||||
ui->castLevel->addItem(QString::fromStdString(s));
|
ui->castLevel->addItem(QString::fromStdString(s));
|
||||||
@@ -347,7 +382,28 @@ void RewardsWidget::saveCurrentVisitInfo(int index)
|
|||||||
int index = ui->lCreatures->item(i, 0)->data(Qt::UserRole).toInt();
|
int index = ui->lCreatures->item(i, 0)->data(Qt::UserRole).toInt();
|
||||||
if(auto * widget = qobject_cast<QSpinBox*>(ui->lCreatures->cellWidget(i, 1)))
|
if(auto * widget = qobject_cast<QSpinBox*>(ui->lCreatures->cellWidget(i, 1)))
|
||||||
if(widget->value())
|
if(widget->value())
|
||||||
vinfo.reward.creatures.emplace_back(VLC->creatures()->getByIndex(index)->getId(), widget->value());
|
vinfo.limiter.creatures.emplace_back(VLC->creatures()->getByIndex(index)->getId(), widget->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
vinfo.limiter.heroes.clear();
|
||||||
|
for(int i = 0; i < ui->lHeroes->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lHeroes->item(i)->checkState() == Qt::Checked)
|
||||||
|
vinfo.limiter.heroes.emplace_back(ui->lHeroes->item(i)->data(Qt::UserRole).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
vinfo.limiter.heroClasses.clear();
|
||||||
|
for(int i = 0; i < ui->lHeroClasses->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lHeroClasses->item(i)->checkState() == Qt::Checked)
|
||||||
|
vinfo.limiter.heroClasses.emplace_back(ui->lHeroClasses->item(i)->data(Qt::UserRole).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
vinfo.limiter.players.clear();
|
||||||
|
for(int i = 0; i < ui->lPlayers->count(); ++i)
|
||||||
|
{
|
||||||
|
if(ui->lPlayers->item(i)->checkState() == Qt::Checked)
|
||||||
|
vinfo.limiter.players.emplace_back(ui->lPlayers->item(i)->data(Qt::UserRole).toInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,10 +501,10 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
|||||||
ui->lHeroExperience->setValue(vinfo.limiter.heroExperience);
|
ui->lHeroExperience->setValue(vinfo.limiter.heroExperience);
|
||||||
ui->lManaPoints->setValue(vinfo.limiter.manaPoints);
|
ui->lManaPoints->setValue(vinfo.limiter.manaPoints);
|
||||||
ui->lManaPercentage->setValue(vinfo.limiter.manaPercentage);
|
ui->lManaPercentage->setValue(vinfo.limiter.manaPercentage);
|
||||||
ui->lAttack->setValue(vinfo.reward.primary[0]);
|
ui->lAttack->setValue(vinfo.limiter.primary[0]);
|
||||||
ui->lDefence->setValue(vinfo.reward.primary[1]);
|
ui->lDefence->setValue(vinfo.limiter.primary[1]);
|
||||||
ui->lPower->setValue(vinfo.reward.primary[2]);
|
ui->lPower->setValue(vinfo.limiter.primary[2]);
|
||||||
ui->lKnowledge->setValue(vinfo.reward.primary[3]);
|
ui->lKnowledge->setValue(vinfo.limiter.primary[3]);
|
||||||
for(int i = 0; i < ui->lResources->rowCount(); ++i)
|
for(int i = 0; i < ui->lResources->rowCount(); ++i)
|
||||||
{
|
{
|
||||||
if(auto * widget = qobject_cast<QSpinBox*>(ui->lResources->cellWidget(i, 1)))
|
if(auto * widget = qobject_cast<QSpinBox*>(ui->lResources->cellWidget(i, 1)))
|
||||||
@@ -472,6 +528,40 @@ void RewardsWidget::loadCurrentVisitInfo(int index)
|
|||||||
ui->lCreatureAmount->setValue(i.count);
|
ui->lCreatureAmount->setValue(i.count);
|
||||||
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
onCreatureAdd(ui->lCreatures, ui->lCreatureId, ui->lCreatureAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto & i : vinfo.limiter.heroes)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lHeroes->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lHeroes->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lHeroes->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto & i : vinfo.limiter.heroClasses)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lHeroClasses->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lHeroClasses->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lHeroClasses->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto & i : vinfo.limiter.players)
|
||||||
|
{
|
||||||
|
for(int e = 0; e < ui->lPlayers->count(); ++e)
|
||||||
|
{
|
||||||
|
if(ui->lPlayers->item(e)->data(Qt::UserRole).toInt() == i.getNum())
|
||||||
|
{
|
||||||
|
ui->lPlayers->item(e)->setCheckState(Qt::Checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewardsWidget::onCreatureAdd(QTableWidget * listWidget, QComboBox * comboWidget, QSpinBox * spinWidget)
|
void RewardsWidget::onCreatureAdd(QTableWidget * listWidget, QComboBox * comboWidget, QSpinBox * spinWidget)
|
||||||
|
@@ -487,6 +487,12 @@
|
|||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="elideMode">
|
||||||
|
<enum>Qt::ElideNone</enum>
|
||||||
|
</property>
|
||||||
|
<property name="usesScrollButtons">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="tabBarAutoHide">
|
<property name="tabBarAutoHide">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@@ -843,7 +849,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="verticalHeaderDefaultSectionSize">
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
<number>21</number>
|
<number>24</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -1185,6 +1191,12 @@
|
|||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="elideMode">
|
||||||
|
<enum>Qt::ElideNone</enum>
|
||||||
|
</property>
|
||||||
|
<property name="usesScrollButtons">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
<property name="tabBarAutoHide">
|
<property name="tabBarAutoHide">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@@ -1229,7 +1241,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="verticalHeaderDefaultSectionSize">
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
<number>21</number>
|
<number>24</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
<column/>
|
<column/>
|
||||||
<column/>
|
<column/>
|
||||||
@@ -1333,7 +1345,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="verticalHeaderDefaultSectionSize">
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
<number>21</number>
|
<number>24</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
<column/>
|
<column/>
|
||||||
<column/>
|
<column/>
|
||||||
@@ -1429,7 +1441,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<attribute name="verticalHeaderDefaultSectionSize">
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
<number>21</number>
|
<number>24</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
<column/>
|
<column/>
|
||||||
<column/>
|
<column/>
|
||||||
@@ -1437,6 +1449,102 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Heroes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_29">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lHeroes">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Hero classes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_30">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lHeroClasses">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_15">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Players</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_31">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="lPlayers">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="isWrapping" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@@ -1095,8 +1095,6 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
if (isInTheMap(guardPos))
|
if (isInTheMap(guardPos))
|
||||||
guardian = getTile(guardPos)->visitableObjects.back();
|
guardian = getTile(guardPos)->visitableObjects.back();
|
||||||
|
|
||||||
assert(guardian == nullptr || dynamic_cast<CGCreature*>(guardian) != nullptr);
|
|
||||||
|
|
||||||
const bool embarking = !h->boat && objectToVisit && objectToVisit->ID == Obj::BOAT;
|
const bool embarking = !h->boat && objectToVisit && objectToVisit->ID == Obj::BOAT;
|
||||||
const bool disembarking = h->boat
|
const bool disembarking = h->boat
|
||||||
&& t.terType->isLand()
|
&& t.terType->isLand()
|
||||||
|
Reference in New Issue
Block a user