mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
New limiter based quests
This commit is contained in:
parent
b7568a160c
commit
1460541ee5
@ -63,9 +63,6 @@ TGoalVec CompleteQuest::decompose() const
|
||||
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:
|
||||
@ -137,7 +134,7 @@ TGoalVec CompleteQuest::missionArt() const
|
||||
|
||||
CaptureObjectsBehavior findArts;
|
||||
|
||||
for(auto art : q.quest->m5arts)
|
||||
for(auto art : q.quest->artifacts)
|
||||
{
|
||||
solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art)));
|
||||
}
|
||||
@ -223,7 +220,7 @@ TGoalVec CompleteQuest::missionResources() const
|
||||
|
||||
TGoalVec CompleteQuest::missionDestroyObj() const
|
||||
{
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return CaptureObjectsBehavior(q.obj).decompose();
|
||||
|
@ -54,9 +54,6 @@ TGoalVec CompleteQuest::getAllPossibleSubgoals()
|
||||
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:
|
||||
@ -137,7 +134,7 @@ TGoalVec CompleteQuest::missionArt() const
|
||||
if(!solutions.empty())
|
||||
return solutions;
|
||||
|
||||
for(auto art : q.quest->m5arts)
|
||||
for(auto art : q.quest->artifacts)
|
||||
{
|
||||
solutions.push_back(sptr(GetArtOfType(art))); //TODO: transport?
|
||||
}
|
||||
@ -165,7 +162,7 @@ TGoalVec CompleteQuest::missionArmy() const
|
||||
if(!solutions.empty())
|
||||
return solutions;
|
||||
|
||||
for(auto creature : q.quest->m6creatures)
|
||||
for(auto creature : q.quest->creatures)
|
||||
{
|
||||
solutions.push_back(sptr(GatherTroops(creature.type->getId(), creature.count)));
|
||||
}
|
||||
@ -179,7 +176,7 @@ TGoalVec CompleteQuest::missionIncreasePrimaryStat() const
|
||||
|
||||
if(solutions.empty())
|
||||
{
|
||||
for(int i = 0; i < q.quest->m2stats.size(); ++i)
|
||||
for(int i = 0; i < q.quest->primary.size(); ++i)
|
||||
{
|
||||
// TODO: library, school and other boost objects
|
||||
logAi->debug("Don't know how to increase primary stat %d", i);
|
||||
@ -195,7 +192,7 @@ TGoalVec CompleteQuest::missionLevel() const
|
||||
|
||||
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->heroLevel);
|
||||
}
|
||||
|
||||
return solutions;
|
||||
@ -227,10 +224,10 @@ TGoalVec CompleteQuest::missionResources() const
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < q.quest->m7resources.size(); ++i)
|
||||
for(int i = 0; i < q.quest->resources.size(); ++i)
|
||||
{
|
||||
if(q.quest->m7resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
|
||||
if(q.quest->resources[i])
|
||||
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->resources[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -246,7 +243,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
||||
{
|
||||
TGoalVec solutions;
|
||||
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
|
||||
auto obj = cb->getObjByQuestIdentifier(q.quest->killTarget);
|
||||
|
||||
if(!obj)
|
||||
return ai->ah->howToVisitObj(q.obj);
|
||||
|
@ -40,7 +40,7 @@ CQuest::CQuest():
|
||||
missionType(MISSION_NONE),
|
||||
progress(NOT_ACTIVE),
|
||||
lastDay(-1),
|
||||
m13489val(0),
|
||||
killTarget(-1),
|
||||
textOption(0),
|
||||
completedOption(0),
|
||||
stackDirection(0),
|
||||
@ -99,7 +99,7 @@ bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
|
||||
ui32 count = 0;
|
||||
ui32 slotsCount = 0;
|
||||
bool hasExtraCreatures = false;
|
||||
for(cre = q->m6creatures.begin(); cre != q->m6creatures.end(); ++cre)
|
||||
for(cre = q->creatures.begin(); cre != q->creatures.end(); ++cre)
|
||||
{
|
||||
for(count = 0, it = army->Slots().begin(); it != army->Slots().end(); ++it)
|
||||
{
|
||||
@ -121,110 +121,53 @@ bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army)
|
||||
|
||||
bool CQuest::checkQuest(const CGHeroInstance * h) const
|
||||
{
|
||||
switch (missionType)
|
||||
if(!heroAllowed(h))
|
||||
return false;
|
||||
|
||||
if(killTarget >= 0)
|
||||
{
|
||||
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;
|
||||
for(const auto & elem : artifactsRequirements)
|
||||
{
|
||||
// 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:
|
||||
if(!CGHeroInstance::cb->getObjByQuestIdentifier(killTarget))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
|
||||
{
|
||||
switch (missionType)
|
||||
for(auto & elem : artifacts)
|
||||
{
|
||||
case CQuest::MISSION_ART:
|
||||
for(auto & elem : m5arts)
|
||||
{
|
||||
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();
|
||||
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)));
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CQuest::MISSION_ARMY:
|
||||
cb->takeCreatures(h->id, m6creatures);
|
||||
break;
|
||||
case CQuest::MISSION_RESOURCES:
|
||||
for (int i = 0; i < 7; ++i)
|
||||
// Disassemble this backpack artifact
|
||||
for(const auto & ci : parts)
|
||||
{
|
||||
cb->giveResource(h->getOwner(), static_cast<EGameResID>(i), -static_cast<int>(m7resources[i]));
|
||||
if(ci.art->getTypeId() != elem)
|
||||
cb->giveHeroNewArtifact(h, ci.art->artType, ArtifactPosition::BACKPACK_START);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cb->takeCreatures(h->id, creatures);
|
||||
cb->giveResources(h->getOwner(), resources);
|
||||
}
|
||||
|
||||
void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components, bool isCustom, bool firstVisit, const CGHeroInstance * h) const
|
||||
{
|
||||
MetaString text;
|
||||
bool failRequirements = (h ? !checkQuest(h) : true);
|
||||
loadComponents(components, h);
|
||||
|
||||
if(firstVisit)
|
||||
{
|
||||
@ -241,20 +184,18 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
switch (missionType)
|
||||
{
|
||||
case MISSION_LEVEL:
|
||||
components.emplace_back(Component::EComponentType::EXPERIENCE, 0, m13489val, 0);
|
||||
if(!isCustom)
|
||||
iwText.replaceNumber(m13489val);
|
||||
iwText.replaceNumber(heroLevel); //TODO: heroLevel
|
||||
break;
|
||||
case MISSION_PRIMARY_STAT:
|
||||
{
|
||||
MetaString loot;
|
||||
for(int i = 0; i < 4; ++i)
|
||||
{
|
||||
if(m2stats[i])
|
||||
if(primary[i])
|
||||
{
|
||||
components.emplace_back(Component::EComponentType::PRIM_SKILL, i, m2stats[i], 0);
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m2stats[i]);
|
||||
loot.replaceNumber(primary[i]);
|
||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
||||
}
|
||||
}
|
||||
@ -268,10 +209,8 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
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());
|
||||
if(!isCustom && !heroes.empty())
|
||||
iwText.replaceRawString(VLC->heroh->getById(heroes.front())->getNameTranslated());
|
||||
break;
|
||||
case MISSION_KILL_CREATURE:
|
||||
{
|
||||
@ -285,9 +224,8 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
case MISSION_ART:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m5arts)
|
||||
for(const auto & elem : artifacts)
|
||||
{
|
||||
components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0);
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
||||
}
|
||||
@ -298,9 +236,8 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
case MISSION_ARMY:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m6creatures)
|
||||
for(const auto & elem : creatures)
|
||||
{
|
||||
components.emplace_back(elem);
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceCreatureName(elem);
|
||||
}
|
||||
@ -313,11 +250,10 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
MetaString loot;
|
||||
for(int i = 0; i < 7; ++i)
|
||||
{
|
||||
if(m7resources[i])
|
||||
if(resources[i])
|
||||
{
|
||||
components.emplace_back(Component::EComponentType::RESOURCE, i, m7resources[i], 0);
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m7resources[i]);
|
||||
loot.replaceNumber(resources[i]);
|
||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
||||
}
|
||||
}
|
||||
@ -326,9 +262,8 @@ void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components
|
||||
}
|
||||
break;
|
||||
case MISSION_PLAYER:
|
||||
components.emplace_back(Component::EComponentType::FLAG, m13489val, 0, 0);
|
||||
if(!isCustom)
|
||||
iwText.replaceLocalString(EMetaText::COLOR, m13489val);
|
||||
if(!isCustom && !players.empty())
|
||||
iwText.replaceLocalString(EMetaText::COLOR, players.front());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -349,17 +284,17 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||
switch(missionType)
|
||||
{
|
||||
case MISSION_LEVEL:
|
||||
ms.replaceNumber(m13489val);
|
||||
ms.replaceNumber(heroLevel);
|
||||
break;
|
||||
case MISSION_PRIMARY_STAT:
|
||||
{
|
||||
MetaString loot;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (m2stats[i])
|
||||
if (primary[i])
|
||||
{
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m2stats[i]);
|
||||
loot.replaceNumber(primary[i]);
|
||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
||||
}
|
||||
}
|
||||
@ -375,7 +310,7 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||
case MISSION_ART:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m5arts)
|
||||
for(const auto & elem : artifacts)
|
||||
{
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
||||
@ -386,7 +321,7 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||
case MISSION_ARMY:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m6creatures)
|
||||
for(const auto & elem : creatures)
|
||||
{
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceCreatureName(elem);
|
||||
@ -399,10 +334,10 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||
MetaString loot;
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
if (m7resources[i])
|
||||
if (resources[i])
|
||||
{
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m7resources[i]);
|
||||
loot.replaceNumber(resources[i]);
|
||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
||||
}
|
||||
}
|
||||
@ -410,10 +345,10 @@ void CQuest::getRolloverText(MetaString &ms, bool onHover) const
|
||||
}
|
||||
break;
|
||||
case MISSION_HERO:
|
||||
ms.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
|
||||
ms.replaceRawString(VLC->heroh->getById(heroes.front())->getNameTranslated());
|
||||
break;
|
||||
case MISSION_PLAYER:
|
||||
ms.replaceRawString(VLC->generaltexth->colors[m13489val]);
|
||||
ms.replaceRawString(VLC->generaltexth->colors[players.front()]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -427,18 +362,18 @@ void CQuest::getCompletionText(MetaString &iwText) const
|
||||
{
|
||||
case CQuest::MISSION_LEVEL:
|
||||
if (!isCustomComplete)
|
||||
iwText.replaceNumber(m13489val);
|
||||
iwText.replaceNumber(heroLevel);
|
||||
break;
|
||||
case CQuest::MISSION_PRIMARY_STAT:
|
||||
{
|
||||
MetaString loot;
|
||||
assert(m2stats.size() <= 4);
|
||||
for (int i = 0; i < m2stats.size(); ++i)
|
||||
assert(primary.size() <= 4);
|
||||
for (int i = 0; i < primary.size(); ++i)
|
||||
{
|
||||
if (m2stats[i])
|
||||
if (primary[i])
|
||||
{
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m2stats[i]);
|
||||
loot.replaceNumber(primary[i]);
|
||||
loot.replaceRawString(VLC->generaltexth->primarySkillNames[i]);
|
||||
}
|
||||
}
|
||||
@ -449,7 +384,7 @@ void CQuest::getCompletionText(MetaString &iwText) const
|
||||
case CQuest::MISSION_ART:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m5arts)
|
||||
for(const auto & elem : artifacts)
|
||||
{
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceLocalString(EMetaText::ART_NAMES, elem);
|
||||
@ -461,7 +396,7 @@ void CQuest::getCompletionText(MetaString &iwText) const
|
||||
case CQuest::MISSION_ARMY:
|
||||
{
|
||||
MetaString loot;
|
||||
for(const auto & elem : m6creatures)
|
||||
for(const auto & elem : creatures)
|
||||
{
|
||||
loot.appendRawString("%s");
|
||||
loot.replaceCreatureName(elem);
|
||||
@ -475,10 +410,10 @@ void CQuest::getCompletionText(MetaString &iwText) const
|
||||
MetaString loot;
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
if (m7resources[i])
|
||||
if (resources[i])
|
||||
{
|
||||
loot.appendRawString("%d %s");
|
||||
loot.replaceNumber(m7resources[i]);
|
||||
loot.replaceNumber(resources[i]);
|
||||
loot.replaceLocalString(EMetaText::RES_NAMES, i);
|
||||
}
|
||||
}
|
||||
@ -492,22 +427,16 @@ void CQuest::getCompletionText(MetaString &iwText) const
|
||||
addReplacements(iwText, completedText.toString());
|
||||
break;
|
||||
case MISSION_HERO:
|
||||
if (!isCustomComplete)
|
||||
iwText.replaceRawString(VLC->heroh->objects[m13489val]->getNameTranslated());
|
||||
if (!isCustomComplete && !heroes.empty())
|
||||
iwText.replaceRawString(VLC->heroh->getById(heroes.front())->getNameTranslated());
|
||||
break;
|
||||
case MISSION_PLAYER:
|
||||
if (!isCustomComplete)
|
||||
iwText.replaceRawString(VLC->generaltexth->colors[m13489val]);
|
||||
if (!isCustomComplete && !players.empty())
|
||||
iwText.replaceRawString(VLC->generaltexth->colors[players.front()]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CQuest::addArtifactID(const ArtifactID & id)
|
||||
{
|
||||
m5arts.push_back(id);
|
||||
++artifactsRequirements[id];
|
||||
}
|
||||
|
||||
void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
|
||||
{
|
||||
auto q = handler.enterStruct(fieldName);
|
||||
@ -522,6 +451,8 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi
|
||||
isCustomNext = !nextVisitText.empty();
|
||||
isCustomComplete = !completedText.empty();
|
||||
}
|
||||
|
||||
Rewardable::Limiter::serializeJson(handler);
|
||||
|
||||
static const std::vector<std::string> MISSION_TYPE_JSON =
|
||||
{
|
||||
@ -530,57 +461,64 @@ void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fi
|
||||
|
||||
handler.serializeEnum("missionType", missionType, Emission::MISSION_NONE, MISSION_TYPE_JSON);
|
||||
handler.serializeInt("timeLimit", lastDay, -1);
|
||||
handler.serializeInstance<int>("killTarget", killTarget, -1);
|
||||
|
||||
switch (missionType)
|
||||
if(!handler.saving)
|
||||
{
|
||||
case MISSION_NONE:
|
||||
break;
|
||||
case MISSION_LEVEL:
|
||||
handler.serializeInt("heroLevel", m13489val, -1);
|
||||
break;
|
||||
case MISSION_PRIMARY_STAT:
|
||||
switch (missionType)
|
||||
{
|
||||
auto primarySkills = handler.enterStruct("primarySkills");
|
||||
if(!handler.saving)
|
||||
m2stats.resize(GameConstants::PRIMARY_SKILLS);
|
||||
|
||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
||||
handler.serializeInt(NPrimarySkill::names[i], m2stats[i], 0);
|
||||
}
|
||||
break;
|
||||
case MISSION_KILL_HERO:
|
||||
case MISSION_KILL_CREATURE:
|
||||
handler.serializeInstance<ui32>("killTarget", m13489val, static_cast<ui32>(-1));
|
||||
break;
|
||||
case MISSION_ART:
|
||||
//todo: ban artifacts
|
||||
handler.serializeIdArray<ArtifactID>("artifacts", m5arts);
|
||||
break;
|
||||
case MISSION_ARMY:
|
||||
{
|
||||
auto a = handler.enterArray("creatures");
|
||||
a.serializeStruct(m6creatures);
|
||||
}
|
||||
break;
|
||||
case MISSION_RESOURCES:
|
||||
{
|
||||
auto r = handler.enterStruct("resources");
|
||||
|
||||
for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
|
||||
case MISSION_NONE:
|
||||
break;
|
||||
case MISSION_LEVEL:
|
||||
handler.serializeInt("heroLevel", heroLevel, -1);
|
||||
break;
|
||||
case MISSION_PRIMARY_STAT:
|
||||
{
|
||||
auto primarySkills = handler.enterStruct("primarySkills");
|
||||
for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
|
||||
handler.serializeInt(NPrimarySkill::names[i], primary[i], 0);
|
||||
}
|
||||
break;
|
||||
case MISSION_KILL_HERO:
|
||||
case MISSION_KILL_CREATURE:
|
||||
break;
|
||||
case MISSION_ART:
|
||||
handler.serializeIdArray<ArtifactID>("artifacts", artifacts);
|
||||
break;
|
||||
case MISSION_ARMY:
|
||||
{
|
||||
handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], m7resources[idx], 0);
|
||||
auto a = handler.enterArray("creatures");
|
||||
a.serializeStruct(creatures);
|
||||
}
|
||||
break;
|
||||
case MISSION_RESOURCES:
|
||||
{
|
||||
auto r = handler.enterStruct("resources");
|
||||
|
||||
for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++)
|
||||
{
|
||||
handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], resources[idx], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MISSION_HERO:
|
||||
{
|
||||
ui32 temp;
|
||||
handler.serializeId<ui32, ui32, HeroTypeID>("hero", temp, 0);
|
||||
heroes.emplace_back(temp);
|
||||
}
|
||||
break;
|
||||
case MISSION_PLAYER:
|
||||
{
|
||||
ui32 temp;
|
||||
handler.serializeId<ui32, ui32, PlayerColor>("player", temp, PlayerColor::NEUTRAL);
|
||||
players.emplace_back(temp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logGlobal->error("Invalid quest mission type");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MISSION_HERO:
|
||||
handler.serializeId<ui32, ui32, HeroTypeID>("hero", m13489val, 0);
|
||||
break;
|
||||
case MISSION_PLAYER:
|
||||
handler.serializeId<ui32, ui32, PlayerColor>("player", m13489val, PlayerColor::NEUTRAL);
|
||||
break;
|
||||
default:
|
||||
logGlobal->error("Invalid quest mission type");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
@ -803,7 +741,7 @@ int CGSeerHut::checkDirection() 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)
|
||||
return nullptr;
|
||||
assert(o && (o->ID == Obj::HERO || o->ID == Obj::PRISON));
|
||||
@ -812,7 +750,7 @@ const CGHeroInstance * CGSeerHut::getHeroToKill(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)
|
||||
return nullptr;
|
||||
assert(o && o->ID == Obj::MONSTER);
|
||||
|
@ -17,10 +17,8 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGCreature;
|
||||
|
||||
class DLL_LINKAGE CQuest final
|
||||
class DLL_LINKAGE CQuest: public Rewardable::Limiter
|
||||
{
|
||||
mutable std::unordered_map<ArtifactID, unsigned, ArtifactID::hash> artifactsRequirements; // artifact ID -> required count
|
||||
|
||||
public:
|
||||
enum Emission {
|
||||
MISSION_NONE = 0,
|
||||
@ -54,12 +52,7 @@ public:
|
||||
Emission missionType;
|
||||
Eprogress progress;
|
||||
si32 lastDay; //after this day (first day is 0) mission cannot be completed; if -1 - no limit
|
||||
|
||||
ui32 m13489val;
|
||||
std::vector<ui32> m2stats;
|
||||
std::vector<ArtifactID> m5arts; // artifact IDs. Add IDs through addArtifactID(), not directly to the field.
|
||||
std::vector<CStackBasicDescriptor> m6creatures; //pair[cre id, cre count], CreatureSet info irrelevant
|
||||
TResources m7resources;
|
||||
int killTarget;
|
||||
|
||||
// following fields are used only for kill creature/hero missions, the original
|
||||
// objects became inaccessible after their removal, so we need to store info
|
||||
@ -85,7 +78,6 @@ public:
|
||||
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
|
||||
virtual void completeQuest(IGameCallback *, const CGHeroInstance * h) const;
|
||||
virtual void addReplacements(MetaString &out, const std::string &base) const;
|
||||
void addArtifactID(const ArtifactID & id);
|
||||
|
||||
bool operator== (const CQuest & quest) const
|
||||
{
|
||||
@ -98,11 +90,6 @@ public:
|
||||
h & missionType;
|
||||
h & progress;
|
||||
h & lastDay;
|
||||
h & m13489val;
|
||||
h & m2stats;
|
||||
h & m5arts;
|
||||
h & m6creatures;
|
||||
h & m7resources;
|
||||
h & textOption;
|
||||
h & stackToKill;
|
||||
h & stackDirection;
|
||||
@ -115,6 +102,7 @@ public:
|
||||
h & isCustomNext;
|
||||
h & isCustomComplete;
|
||||
h & completedOption;
|
||||
h & static_cast<Rewardable::Limiter&>(*this);
|
||||
}
|
||||
|
||||
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);
|
||||
|
@ -1871,7 +1871,7 @@ void CMapLoaderH3M::readSeerHutQuest(CGSeerHut * hut, const int3 & position, con
|
||||
if(artID != ArtifactID::NONE)
|
||||
{
|
||||
//not none quest
|
||||
hut->quest->addArtifactID(artID);
|
||||
hut->quest->artifacts.push_back(artID);
|
||||
hut->quest->missionType = CQuest::MISSION_ART;
|
||||
}
|
||||
else
|
||||
@ -1986,10 +1986,9 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||
return;
|
||||
case CQuest::MISSION_PRIMARY_STAT:
|
||||
{
|
||||
guard->quest->m2stats.resize(4);
|
||||
for(int x = 0; x < 4; ++x)
|
||||
{
|
||||
guard->quest->m2stats[x] = reader->readUInt8();
|
||||
guard->quest->primary[x] = reader->readUInt8();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1997,7 +1996,7 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||
case CQuest::MISSION_KILL_HERO:
|
||||
case CQuest::MISSION_KILL_CREATURE:
|
||||
{
|
||||
guard->quest->m13489val = reader->readUInt32();
|
||||
guard->quest->killTarget = reader->readUInt32();
|
||||
break;
|
||||
}
|
||||
case CQuest::MISSION_ART:
|
||||
@ -2006,7 +2005,7 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||
for(int yy = 0; yy < artNumber; ++yy)
|
||||
{
|
||||
auto artid = reader->readArtifact();
|
||||
guard->quest->addArtifactID(artid);
|
||||
guard->quest->artifacts.push_back(artid);
|
||||
map->allowedArtifact[artid] = false; //these are unavailable for random generation
|
||||
}
|
||||
break;
|
||||
@ -2014,29 +2013,29 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||
case CQuest::MISSION_ARMY:
|
||||
{
|
||||
int typeNumber = reader->readUInt8();
|
||||
guard->quest->m6creatures.resize(typeNumber);
|
||||
guard->quest->creatures.resize(typeNumber);
|
||||
for(int hh = 0; hh < typeNumber; ++hh)
|
||||
{
|
||||
guard->quest->m6creatures[hh].type = VLC->creh->objects[reader->readCreature()];
|
||||
guard->quest->m6creatures[hh].count = reader->readUInt16();
|
||||
guard->quest->creatures[hh].type = VLC->creh->objects[reader->readCreature()];
|
||||
guard->quest->creatures[hh].count = reader->readUInt16();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CQuest::MISSION_RESOURCES:
|
||||
{
|
||||
for(int x = 0; x < 7; ++x)
|
||||
guard->quest->m7resources[x] = reader->readUInt32();
|
||||
guard->quest->resources[x] = reader->readUInt32();
|
||||
|
||||
break;
|
||||
}
|
||||
case CQuest::MISSION_HERO:
|
||||
{
|
||||
guard->quest->m13489val = reader->readHero().getNum();
|
||||
guard->quest->heroes.push_back(reader->readHero());
|
||||
break;
|
||||
}
|
||||
case CQuest::MISSION_PLAYER:
|
||||
{
|
||||
guard->quest->m13489val = reader->readPlayer().getNum();
|
||||
guard->quest->players.push_back(reader->readPlayer());
|
||||
break;
|
||||
}
|
||||
case CQuest::MISSION_HOTA_MULTI:
|
||||
@ -2045,22 +2044,19 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard, const int3 & position)
|
||||
|
||||
if(missionSubID == 0)
|
||||
{
|
||||
guard->quest->missionType = CQuest::MISSION_NONE; //TODO: CQuest::MISSION_HOTA_HERO_CLASS;
|
||||
guard->quest->missionType = CQuest::MISSION_HOTA_HERO_CLASS;
|
||||
std::set<HeroClassID> heroClasses;
|
||||
reader->readBitmaskHeroClassesSized(heroClasses, false);
|
||||
|
||||
logGlobal->warn("Map '%s': Quest at %s 'Belong to one of %d classes' is not implemented!", mapName, position.toString(), heroClasses.size());
|
||||
for(auto & hc : heroClasses)
|
||||
guard->quest->heroClasses.push_back(hc);
|
||||
break;
|
||||
}
|
||||
if(missionSubID == 1)
|
||||
{
|
||||
guard->quest->missionType = CQuest::MISSION_NONE; //TODO: CQuest::MISSION_HOTA_REACH_DATE;
|
||||
uint32_t daysPassed = reader->readUInt32();
|
||||
|
||||
logGlobal->warn("Map '%s': Quest at %s 'Wait till %d days passed' is not implemented!", mapName, position.toString(), daysPassed);
|
||||
guard->quest->missionType = CQuest::MISSION_HOTA_REACH_DATE;
|
||||
guard->quest->daysPassed = reader->readUInt32();
|
||||
break;
|
||||
}
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -146,6 +146,54 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
|
||||
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)
|
||||
comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0);
|
||||
|
||||
if (manaPoints || manaPercentage > 0)
|
||||
comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, 0, 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)
|
||||
{
|
||||
handler.serializeInt("dayOfWeek", dayOfWeek);
|
||||
|
@ -17,6 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGHeroInstance;
|
||||
class CStackBasicDescriptor;
|
||||
struct Component;
|
||||
|
||||
namespace Rewardable {
|
||||
|
||||
@ -78,9 +79,13 @@ struct DLL_LINKAGE Limiter
|
||||
LimitersList noneOf;
|
||||
|
||||
Limiter();
|
||||
~Limiter();
|
||||
virtual ~Limiter();
|
||||
|
||||
bool heroAllowed(const CGHeroInstance * hero) const;
|
||||
|
||||
/// Generates list of components that describes reward for a specific hero
|
||||
virtual void loadComponents(std::vector<Component> & comps,
|
||||
const CGHeroInstance * h) const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ struct DLL_LINKAGE Reward
|
||||
si32 calculateManaPoints(const CGHeroInstance * h) const;
|
||||
|
||||
Reward();
|
||||
~Reward();
|
||||
virtual ~Reward();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -464,7 +464,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->artifacts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
@ -515,7 +515,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->artifacts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
@ -540,7 +540,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->artifacts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user