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