25#include <unordered_map>
31static std::unordered_map<int, Quest> quests;
34template<
typename Container,
typename Value>
35static bool contains(
const Container &container,
const Value &value)
37 return std::find(container.begin(), container.end(), value) != container.end();
51 Quest &quest = quests[varId];
55 if (child.name() ==
"effect")
58 child.attribute(
"map", effect.
map);
59 child.attribute(
"npc", effect.
npcId);
61 child.attribute(
"value", effect.
values);
65 Log::warn(
"effect node for var %d is missing required attributes", varId);
68 else if (child.name() ==
"quest")
71 child.attribute(
"name", state.
name);
72 child.attribute(
"group", state.
group);
73 child.attribute(
"incomplete", state.
incomplete);
74 child.attribute(
"complete", state.
complete);
78 Log::warn(
"quest node for var %d ('%s') has neither 'complete' nor 'incomplete' values",
79 varId, state.
name.c_str());
83 for (
auto questChild : child.children())
86 std::string_view tag = questChild.name();
89 else if (tag ==
"name")
91 else if (tag ==
"reward")
93 else if (tag ==
"questgiver" || tag ==
"giver")
95 else if (tag ==
"coordinates")
97 else if (tag ==
"npc")
101 Log::warn(
"unknown quest row type '%s' for var %d ('%s')",
102 tag.data(), varId, state.
name.c_str());
107 row.
text = questChild.textContent();
111 questChild.attribute(
"x", row.
x);
112 questChild.attribute(
"y", row.
y);
126 return !quests.empty();
131static std::string_view baseName(
const std::string &fileName)
133 auto pos = fileName.find_last_of(
'.');
134 return pos == std::string::npos ? fileName : std::string_view(fileName.data(), pos);
138 const std::string &mapName)
142 for (
auto &[var, quest] : std::as_const(quests))
144 auto value = questVars.
get(var);
146 for (
auto &effect : quest.effects)
148 if (baseName(effect.map) != mapName)
150 if (!contains(effect.values, value))
153 activeEffects.
set(effect.npcId, effect.statusEffectId);
157 return activeEffects;
163 std::vector<QuestEntry> activeQuests;
165 for (
auto &[varId, quest] : std::as_const(quests))
167 auto value = questVars.
get(varId);
169 for (
auto &state : quest.states)
171 bool matchesIncomplete = contains(state.incomplete, value);
172 bool matchesComplete = contains(state.complete, value);
174 if (skipCompleted && matchesComplete)
177 if (matchesIncomplete || matchesComplete)
179 QuestEntry &entry = activeQuests.emplace_back();
182 entry.
state = &state;
190static std::pair<int, int> countQuestEntries(
const Quest &quest,
int value)
192 int totalEntries = 0;
193 int completedEntries = 0;
195 for (
const auto &state : quest.states)
197 bool matchesIncomplete = contains(state.incomplete, value);
198 bool matchesComplete = contains(state.complete, value);
200 if (matchesIncomplete || matchesComplete)
208 return { totalEntries, completedEntries };
213 if (newValue == oldValue)
216 auto questIt = quests.find(varId);
217 if (questIt == quests.end())
220 const Quest &quest = questIt->second;
222 auto [oldQuestEntries, oldCompletedEntries] = countQuestEntries(quest, oldValue);
223 auto [newQuestEntries, newCompletedEntries] = countQuestEntries(quest, newValue);
225 if (newCompletedEntries > oldCompletedEntries)
227 if (newQuestEntries > oldQuestEntries)
void set(Key key, Value value)
Children children() const
bool attribute(const char *name, T &value) const
void warn(const char *log_text,...) LOG_PRINTF_ATTR
QuestChange questChange(int varId, int oldValue, int newValue)
QuestEffectMap getActiveEffects(const QuestVars &questVars, const std::string &mapName)
void readQuestVarNode(XML::Node node, const std::string &filename)
std::vector< QuestEntry > getQuestsEntries(const QuestVars &questVars, bool skipCompleted)
std::vector< int > values
std::vector< int > incomplete
std::vector< QuestRow > rows
std::vector< int > complete
std::vector< QuestEffect > effects
std::vector< QuestState > states