ManaPlus
questswindow.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2012-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
23 
24 #include "actormanager.h"
25 #include "configuration.h"
26 #include "effectmanager.h"
27 
28 #include "being/localplayer.h"
29 
30 #include "enums/gui/layouttype.h"
31 
32 #include "gui/gui.h"
33 
34 #include "gui/fonts/font.h"
35 
36 #include "gui/models/questsmodel.h"
37 
39 
40 #include "gui/widgets/button.h"
41 #include "gui/widgets/browserbox.h"
44 #include "gui/widgets/layout.h"
47 #include "gui/widgets/scrollarea.h"
48 
49 #include "utils/delete2.h"
50 #include "utils/foreach.h"
51 #include "utils/gettext.h"
52 
53 #include "resources/questeffect.h"
54 #include "resources/questitem.h"
55 
56 #include "resources/db/questdb.h"
57 
58 #include "resources/map/map.h"
59 
60 #include "debug.h"
61 
63 
65  // TRANSLATORS: quests window name
66  Window(_("Quests"), Modal_false, nullptr, "quests.xml"),
68  mQuestsModel(new QuestsModel),
69  mQuestsListBox(CREATEWIDGETR(ExtendedListBox,
70  this, mQuestsModel, "extendedlistbox.xml", 13)),
71  mQuestScrollArea(new ScrollArea(this, mQuestsListBox,
72  fromBool(getOptionBool("showlistbackground", false), Opaque),
73  "quests_list_background.xml")),
74  mItemLinkHandler(new ItemLinkHandler),
75  mText(new BrowserBox(this, Opaque_true,
76  "browserbox.xml")),
77  mTextScrollArea(new ScrollArea(this, mText,
78  fromBool(getOptionBool("showtextbackground", false), Opaque),
79  "quests_text_background.xml")),
80  // TRANSLATORS: quests window button
81  mCloseButton(new Button(this, _("Close"), "close", BUTTON_SKIN, this)),
82  mCompleteIcon(Theme::getImageFromThemeXml("complete_icon.xml", "")),
83  mIncompleteIcon(Theme::getImageFromThemeXml("incomplete_icon.xml", "")),
84  mMapEffects(),
85  mVars(nullptr),
88  mNpcEffects(),
89  mQuestLinks(),
90  mQuestReverseLinks(),
91  mNewQuestEffectId(paths.getIntValue("newQuestEffectId")),
92  mCompleteQuestEffectId(paths.getIntValue("completeQuestEffectId")),
93  mMap(nullptr)
94 {
95  setWindowName("Quests");
96  setResizable(true);
97  setCloseButton(true);
98  setStickyButtonLock(true);
99  setSaveVisible(true);
100 
101  setDefaultSize(400, 350, ImagePosition::RIGHT, 0, 0);
102  setMinWidth(310);
103  setMinHeight(220);
104 
105  if (setupWindow != nullptr)
107 
108  mQuestsListBox->setActionEventId("select");
110 
115  mQuestsListBox->setWidth(500);
116  if ((gui == nullptr) || gui->getNpcFont()->getHeight() < 20)
118  else
120 
121  ContainerPlacer placer(nullptr, nullptr);
122  placer = getPlacer(0, 0);
123 
124  placer(0, 0, mQuestScrollArea, 4, 3).setPadding(3);
125  placer(4, 0, mTextScrollArea, 4, 3).setPadding(3);
126  placer(7, 3, mCloseButton, 1, 1);
127 
128  Layout &layout = getLayout();
129  layout.setRowHeight(0, LayoutType::SET);
130 
131  loadWindowState();
132  enableVisibleSound(true);
133  QuestDb::load();
137 }
138 
140 {
142 
143  QuestDb::unload();
144 
146  mQuestLinks.clear();
147  mQuestReverseLinks.clear();
148  if (mCompleteIcon != nullptr)
149  {
150  mCompleteIcon->decRef();
151  mCompleteIcon = nullptr;
152  }
153  if (mIncompleteIcon != nullptr)
154  {
155  mIncompleteIcon->decRef();
156  mIncompleteIcon = nullptr;
157  }
158 }
159 
161 {
162  const std::string &eventId = event.getId();
163  if (eventId == "select")
164  {
165  const int id = mQuestsListBox->getSelected();
166  if (id < 0)
167  return;
168  showQuest(mQuestLinks[id]);
169  }
170  else if (eventId == "close")
171  {
173  }
174 }
175 
176 void QuestsWindow::updateQuest(const int var,
177  const int val1,
178  const int val2,
179  const int val3,
180  const int time1)
181 {
182  (*mVars)[var] = QuestVar(val1, val2, val3, time1);
183 }
184 
185 void QuestsWindow::rebuild(const bool playSound)
186 {
187  mQuestsModel->clear();
188  mQuestLinks.clear();
189  mQuestReverseLinks.clear();
190  StringVect &names = mQuestsModel->getNames();
191  STD_VECTOR<Image*> &images = mQuestsModel->getImages();
192  STD_VECTOR<QuestItem*> complete;
193  STD_VECTOR<QuestItem*> incomplete;
194  STD_VECTOR<QuestItem*> hidden;
195  int updatedQuest = -1;
196  int newCompleteStatus = -1;
197 
199  {
200  const int var = (*it).first;
201  const QuestVar &val = (*it).second;
202  const STD_VECTOR<QuestItem*> &quests = (*mQuests)[var];
203  FOR_EACH (STD_VECTOR<QuestItem*>::const_iterator, it2, quests)
204  {
205  if (*it2 == nullptr)
206  continue;
207  QuestItem *const quest = *it2;
208  // complete quest
209  if (quest->complete.find(val.var1) != quest->complete.end())
210  {
211  complete.push_back(quest);
212  }
213  // incomplete quest
214  else if (quest->incomplete.find(val.var1) !=
215  quest->incomplete.end())
216  {
217  incomplete.push_back(quest);
218  }
219  // hidden quest
220  else
221  {
222  hidden.push_back(quest);
223  }
224  }
225  }
226 
227  int k = 0;
228 
229  for (STD_VECTOR<QuestItem*>::const_iterator it = complete.begin(),
230  it_end = complete.end(); it != it_end; ++ it, k ++)
231  {
232  QuestItem *const quest = *it;
233  if (quest->completeFlag == 0 || (quest->broken
234  && quest->completeFlag == -1))
235  {
236  updatedQuest = k;
237  newCompleteStatus = 1;
238  }
239  quest->completeFlag = 1;
240  mQuestLinks.push_back(quest);
241  mQuestReverseLinks[quest->var] = k;
242  names.push_back(quest->name);
243  if (mCompleteIcon != nullptr)
244  {
245  mCompleteIcon->incRef();
246  images.push_back(mCompleteIcon);
247  }
248  else
249  {
250  images.push_back(nullptr);
251  }
252  }
253 
254  for (STD_VECTOR<QuestItem*>::const_iterator it = incomplete.begin(),
255  it_end = incomplete.end(); it != it_end; ++ it, k ++)
256  {
257  QuestItem *const quest = *it;
258  if (quest->completeFlag == -1)
259  {
260  updatedQuest = k;
261  newCompleteStatus = 0;
262  }
263  quest->completeFlag = 0;
264  mQuestLinks.push_back(quest);
265  mQuestReverseLinks[quest->var] = k;
266  names.push_back(quest->name);
267  if (mIncompleteIcon != nullptr)
268  {
269  mIncompleteIcon->incRef();
270  images.push_back(mIncompleteIcon);
271  }
272  else
273  {
274  images.push_back(nullptr);
275  }
276  }
277 
278  FOR_EACH (STD_VECTOR<QuestItem*>::const_iterator, it, hidden)
279  (*it)->completeFlag = -1;
280 
281  if (updatedQuest == -1 || updatedQuest >= CAST_S32(
282  mQuestLinks.size()))
283  {
284  updatedQuest = CAST_S32(mQuestLinks.size() - 1);
285  }
286  if (updatedQuest >= 0)
287  {
288  mQuestsListBox->setSelected(updatedQuest);
289  showQuest(mQuestLinks[updatedQuest]);
290  if (playSound && (effectManager != nullptr))
291  {
292  switch (newCompleteStatus)
293  {
294  case 0:
296  break;
297  case 1:
299  localPlayer,
300  0);
301  break;
302  default:
303  break;
304  }
305  }
306  }
307  updateEffects();
308 }
309 
310 void QuestsWindow::showQuest(const QuestItem *const quest)
311 {
312  if (quest == nullptr)
313  return;
314 
315  const STD_VECTOR<QuestItemText> &texts = quest->texts;
316  const QuestVar &var = (*mVars)[quest->var];
317  const std::string var1 = toString(var.var1);
318  const std::string var2 = toString(var.var2);
319  const std::string var3 = toString(var.var3);
320  const std::string timeStr = timeDiffToString(var.time1);
321  mText->clearRows();
322  FOR_EACH (STD_VECTOR<QuestItemText>::const_iterator, it, texts)
323  {
324  const QuestItemText &data = *it;
325  std::string text = data.text;
326  replaceAll(text, "{@@var1}", var1);
327  replaceAll(text, "{@@var2}", var2);
328  replaceAll(text, "{@@var3}", var3);
329  replaceAll(text, "{@@time}", timeStr);
330  switch (data.type)
331  {
332  case QuestType::TEXT:
333  default:
334  mText->addRow(text,
335  false);
336  break;
337  case QuestType::NAME:
338  mText->addRow(std::string("[").append(text).append("]"),
339  false);
340  break;
341  case QuestType::REWARD:
342  mText->addRow(std::string(
343  // TRANSLATORS: quest reward
344  _("Reward:")).append(
345  " ").append(
346  text),
347  false);
348  break;
349  case QuestType::GIVER:
350  mText->addRow(std::string(
351  // TRANSLATORS: quest giver name
352  _("Quest Giver:")).append(
353  " ").append(
354  text),
355  false);
356  break;
357  case QuestType::NPC:
358  mText->addRow(std::string(
359  // TRANSLATORS: quest npc name
360  _("Npc:")).append(
361  " ").append(
362  text),
363  false);
364  break;
366  mText->addRow(std::string(
367  strprintf("%s [@@=navigate %s %s|%s@@]",
368  // TRANSLATORS: quest coordinates
369  _("Coordinates:"),
370  data.data1.c_str(),
371  data.data2.c_str(),
372  text.c_str())),
373  false);
374  break;
375  }
376  }
377  mText->updateHeight();
378 }
379 
380 void QuestsWindow::setMap(const Map *const map)
381 {
382  if (mMap != map)
383  {
384  mMap = map;
385  mMapEffects.clear();
386  if (mMap == nullptr)
387  return;
388 
389  const std::string name = mMap->getProperty("shortName",
390  std::string());
391  FOR_EACHP (STD_VECTOR<QuestEffect*>::const_iterator, it, mAllEffects)
392  {
393  const QuestEffect *const effect = *it;
394  if ((effect != nullptr) && name == effect->map)
395  mMapEffects.push_back(effect);
396  }
397  updateEffects();
398  }
399 }
400 
402 {
404  mNpcEffects.clear();
405 
406  FOR_EACH (STD_VECTOR<const QuestEffect*>::const_iterator,
407  it, mMapEffects)
408  {
409  const QuestEffect *const effect = *it;
410  if (effect != nullptr)
411  {
412  const NpcQuestVarMapCIter varIt = mVars->find(effect->var);
413  if (varIt != mVars->end())
414  {
415  const std::set<int> &vals = effect->values;
416  if (vals.find((*mVars)[effect->var].var1) != vals.end())
417  mNpcEffects[effect->id] = effect;
418  }
419  }
420  }
421  if (actorManager == nullptr)
422  return;
423 
424  std::set<BeingTypeId> removeEffects;
425  std::map<BeingTypeId, int> addEffects;
426 
427  // for old effects
428  FOR_EACH (NpcQuestEffectMapCIter, it, oldNpc)
429  {
430  const BeingTypeId id = (*it).first;
431  const QuestEffect *const effect = (*it).second;
432 
433  const NpcQuestEffectMapCIter itNew = mNpcEffects.find(id);
434  if (itNew == mNpcEffects.end())
435  { // in new list no effect for this npc
436  removeEffects.insert(id);
437  }
438  else
439  { // in new list exists effect for this npc
440  const QuestEffect *const newEffect = (*itNew).second;
441  if (effect != newEffect)
442  { // new effects is not equal to old effect
443  addEffects[id] = newEffect->effectId;
444  removeEffects.insert(id);
445  }
446  }
447  }
448 
449  // for new effects
451  {
452  const BeingTypeId id = (*it).first;
453  const QuestEffect *const effect = (*it).second;
454 
455  const NpcQuestEffectMapCIter itNew = oldNpc.find(id);
456  // check if old effect was not present
457  if (itNew == oldNpc.end())
458  addEffects[id] = effect->effectId;
459  }
460  if (!removeEffects.empty() || !addEffects.empty())
461  actorManager->updateEffects(addEffects, removeEffects);
462 }
463 
464 void QuestsWindow::addEffect(Being *const being)
465 {
466  if (being == nullptr)
467  return;
468  const BeingTypeId id = being->getSubType();
469  const std::map<BeingTypeId, const QuestEffect*>::const_iterator
470  it = mNpcEffects.find(id);
471  if (it != mNpcEffects.end())
472  {
473  const QuestEffect *const effect = (*it).second;
474  if (effect != nullptr)
475  being->addSpecialEffect(effect->effectId);
476  }
477 }
478 
479 void QuestsWindow::selectQuest(const int varId)
480 {
481  std::map<int, int>::const_iterator it = mQuestReverseLinks.find(varId);
482  if (it == mQuestReverseLinks.end())
483  return;
484  if (mVisible == Visible_false)
486  const int listPos = (*it).second;
487  if (listPos < 0)
488  return;
489  showQuest(mQuestLinks[listPos]);
490  mQuestsListBox->setSelected(listPos);
492 }
ActorManager * actorManager
int BeingTypeId
Definition: beingtypeid.h:30
#define fromBool(val, name)
Definition: booldefines.h:49
const std::string BUTTON_SKIN
Definition: button.h:89
#define CAST_S32
Definition: cast.h:30
void updateEffects(const std::map< BeingTypeId, int > &addEffects, const std::set< BeingTypeId > &removeEffects) const
Definition: being.h:96
BeingTypeId getSubType() const
Definition: being.h:400
void addSpecialEffect(const int effect)
Definition: being.cpp:4928
void updateHeight()
Definition: browserbox.cpp:851
void addRow(const std::string &row, const bool atTop)
Definition: browserbox.cpp:171
void setLinkHandler(LinkHandler *linkHandler)
Definition: browserbox.cpp:166
void clearRows()
Definition: browserbox.cpp:359
void setOpaque(Opaque opaque)
Definition: browserbox.h:75
Definition: button.h:102
bool trigger(const int id, Being *const being, const int rotation)
StringVect & getNames()
std::vector< Image * > & getImages()
int getHeight() const
Definition: font.cpp:362
Font * getNpcFont() const
Definition: gui.h:178
void setRowHeight(const int n, const int h)
Definition: layoutcell.cpp:128
Definition: layout.h:45
void setRowHeight(unsigned int n)
Definition: listbox.h:159
int getSelected() const
Definition: listbox.h:168
void setSelected(const int selected)
Definition: listbox.cpp:399
Definition: map.h:75
const std::string getProperty(const std::string &name, const std::string &def) const
Definition: properties.h:59
void updateEffects()
QuestsModel * mQuestsModel
Definition: questswindow.h:81
ScrollArea * mQuestScrollArea
Definition: questswindow.h:83
std::vector< const QuestEffect * > mMapEffects
Definition: questswindow.h:90
void addEffect(Being *const being)
Button * mCloseButton
Definition: questswindow.h:87
Image * mCompleteIcon
Definition: questswindow.h:88
NpcQuestEffectMap mNpcEffects
Definition: questswindow.h:96
void action(const ActionEvent &event)
int mCompleteQuestEffectId
Definition: questswindow.h:100
ExtendedListBox * mQuestsListBox
Definition: questswindow.h:82
ItemLinkHandler * mItemLinkHandler
Definition: questswindow.h:84
std::map< int, int > mQuestReverseLinks
Definition: questswindow.h:98
NpcQuestVarMap * mVars
Definition: questswindow.h:91
std::map< int, std::vector< QuestItem * > > * mQuests
Definition: questswindow.h:92
int mNewQuestEffectId
Definition: questswindow.h:99
void updateQuest(const int var, const int val1, const int val2, const int val3, const int time1)
std::vector< QuestItem * > mQuestLinks
Definition: questswindow.h:97
void rebuild(const bool playSound)
BrowserBox * mText
Definition: questswindow.h:85
ScrollArea * mTextScrollArea
Definition: questswindow.h:86
const Map * mMap
Definition: questswindow.h:101
void selectQuest(const int varId)
void showQuest(const QuestItem *const quest)
std::vector< QuestEffect * > * mAllEffects
Definition: questswindow.h:93
Image * mIncompleteIcon
Definition: questswindow.h:89
void setMap(const Map *const map)
void setHorizontalScrollPolicy(const ScrollPolicy hPolicy)
void registerWindowForReset(Window *const window)
Definition: theme.h:55
void setWidth(const int width)
Definition: widget.cpp:133
virtual void requestMoveToTop()
Definition: widget.cpp:213
void setActionEventId(const std::string &actionEventId)
Definition: widget.h:596
Visible mVisible
Definition: widget.h:963
void addActionListener(ActionListener *const actionListener)
Definition: widget.cpp:252
Definition: window.h:102
void setSaveVisible(const bool save)
Definition: window.h:300
void setResizable(const bool resize)
Definition: window.cpp:627
ContainerPlacer getPlacer(const int x, const int y)
Definition: window.cpp:1391
virtual void setVisible(Visible visible)
Definition: window.cpp:778
Layout & getLayout()
Definition: window.cpp:1365
void setWindowName(const std::string &name)
Definition: window.h:355
void setMinHeight(const int height)
Definition: window.cpp:604
void setMinWidth(const int width)
Definition: window.cpp:591
void enableVisibleSound(bool b)
Definition: window.h:481
void setCloseButton(const bool flag)
Definition: window.cpp:749
void setStickyButtonLock(const bool sticky)
Definition: window.cpp:772
void setDefaultSize()
Definition: window.cpp:1198
void loadWindowState()
Definition: window.cpp:1087
Configuration paths
#define CREATEWIDGETR(type,...)
Definition: createwidget.h:36
#define new
Definition: debug_new.h:147
#define delete2(var)
Definition: delete2.h:25
EffectManager * effectManager
#define FOR_EACHP(type, iter, array)
Definition: foreach.h:31
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define _(s)
Definition: gettext.h:35
Gui * gui
Definition: gui.cpp:111
#define nullptr
Definition: localconsts.h:45
LocalPlayer * localPlayer
uint32_t data
const bool Modal_false
Definition: modal.h:30
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
std::string mMap
Definition: gamerecv.cpp:46
NpcQuestVarMap * getVars()
Definition: questdb.cpp:234
void unload()
Definition: questdb.cpp:216
void load()
Definition: questdb.cpp:47
std::map< int, std::vector< QuestItem * > > * getQuests()
Definition: questdb.cpp:239
std::vector< QuestEffect * > * getAllEffects()
Definition: questdb.cpp:244
@ COORDINATES
Definition: questtype.h:33
std::map< int, std::vector< QuestItem * > > mQuests
Definition: questdb.cpp:43
std::vector< QuestEffect * > mAllEffects
Definition: questdb.cpp:44
const bool Opaque_false
Definition: opaque.h:30
const bool Opaque_true
Definition: opaque.h:30
bool Opaque
Definition: opaque.h:30
QuestsWindow * questsWindow
std::map< BeingTypeId, const QuestEffect * > NpcQuestEffectMap
Definition: questswindow.h:45
NpcQuestEffectMap::const_iterator NpcQuestEffectMapCIter
Definition: questswindow.h:48
NpcQuestVarMap::const_iterator NpcQuestVarMapCIter
Definition: questvar.h:59
SetupWindow * setupWindow
Definition: setupwindow.cpp:64
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)
std::string strprintf(const char *const format,...)
std::string timeDiffToString(int timeDiff)
std::vector< std::string > StringVect
Definition: stringvector.h:29
std::string map
Definition: questeffect.h:45
BeingTypeId id
Definition: questeffect.h:47
std::set< int > values
Definition: questeffect.h:49
std::vector< QuestItemText > texts
Definition: questitem.h:54
int var
Definition: questitem.h:49
bool broken
Definition: questitem.h:56
std::set< int > complete
Definition: questitem.h:53
std::string name
Definition: questitem.h:50
int completeFlag
Definition: questitem.h:55
std::set< int > incomplete
Definition: questitem.h:52
int var2
Definition: questvar.h:53
int var3
Definition: questvar.h:54
int var1
Definition: questvar.h:52
int time1
Definition: questvar.h:55
const bool Visible_false
Definition: visible.h:30
const bool Visible_true
Definition: visible.h:30