xoreos  0.0.5
charfeats.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <algorithm>
26 
27 #include "src/common/util.h"
28 #include "src/common/strutil.h"
29 #include "src/common/uuid.h"
30 
31 #include "src/graphics/graphics.h"
32 
34 
35 #include "src/aurora/talkman.h"
36 #include "src/aurora/2dareg.h"
37 #include "src/aurora/2dafile.h"
38 
46 
47 namespace Engines {
48 
49 namespace NWN {
50 
52  WidgetListItemButton(gui, "ctl_cg_btn_feat",
53  feat.name + "#" + Common::generateIDNumberString(),
54  feat.icon, kMoveButton | kHelpButton),
55  _feat(feat) {
56 
57  // Set maximum width for text.
58  _text->set(feat.name, 230.f);
59 
60  setTag("Item#" + feat.name + "#" + Common::generateIDNumberString());
61 }
62 
64 }
65 
67  dynamic_cast<CharFeats &>(*_gui).showFeatHelp(_feat);
68 }
69 
71  if ((widget.getTag().endsWith("#MoveButtonLeft") || widget.getTag().endsWith("#MoveButtonRight")) &&
72  movable()) {
73  dynamic_cast<CharFeats &>(*_gui).moveFeat(this);
74  }
75 }
76 
78  _choices = &choices;
79  load("cg_feats");
80 
81  _normalFeats = 0;
82  _bonusFeats = 0;
83 
84  _featHelp.reset(new CharHelp("cg_featinfo", console));
85  _featsPopup.reset(new CharFeatsPopup(console));
86 
87  _availListBox = getListBox("AvailBox", true);
88  _knownListBox = getListBox("KnownBox", true);
89 
92 
93  // Update text about the available feats.
94  changeAvailFeats(0, true);
95 
96  // By default, show both general and bonus feats.
97  makeAvailList(1);
98  makeKnownList();
99 
100  getButton("OkButton", true)->setDisabled(true);
101 }
102 
104  _availListBox->lock();
105  _availListBox->clear();
107  _knownListBox->lock();
108  _knownListBox->clear();
110 }
111 
113  while (_knownFeats.size() > 0) {
114  moveFeat(_knownFeats.front(), false);
115  }
116 }
117 
119  if (tag == "AvailBox" || tag == "KnownBox")
121 }
122 
124  _featHelp->setContent(feat.name, feat.description, feat.icon);
125 
126  _featHelp->show();
127  _featHelp->run();
128  _featHelp->hide();
129 }
130 
131 void CharFeats::moveFeat(FeatItem feat, bool toKnownFeats, bool rebuild) {
132  // Check if there is enough remaining feats available.
133  if (toKnownFeats) {
134  if (_bonusFeats + _normalFeats == 0)
135  return;
136  if (_bonusFeats == 0 && feat.list > 1)
137  return;
138  if (_normalFeats == 0 && feat.list < 1)
139  return;
140  }
141 
142  std::list<FeatItem> &toList = (toKnownFeats) ? _knownFeats : _availFeats;
143  std::list<FeatItem> &fromList = (toKnownFeats) ? _availFeats : _knownFeats;
144  int8 diff = (toKnownFeats) ? -1 : 1;
145 
146  for (std::list<FeatItem>::iterator aF = fromList.begin(); aF != fromList.end(); ++aF) {
147  if ((*aF).featId != feat.featId)
148  continue;
149 
150  toList.push_back((*aF));
151  fromList.erase(aF);
152  break;
153  }
154 
155  bool isNormalFeat = true;
156  if (toKnownFeats) {
157  isNormalFeat = (feat.list < 2 && _bonusFeats == 0) || (feat.list == 0);
158  } else {
159  isNormalFeat = (feat.list == 0) || (feat.list < 2 && _bonusFeats > 0);
160  }
161 
162  changeAvailFeats(diff, isNormalFeat, rebuild);
163 }
164 
166  WidgetListBox *fromListBox = dynamic_cast<WidgetListBox *>(item->_owner);
167 
168  // Check if there is enough remaining feats available.
169  if (!fromListBox || ((fromListBox->getTag() == "AvailBox") && ((_bonusFeats + _normalFeats) == 0)))
170  return;
171 
172  if (!item->_feat.isMasterFeat) {
173  item->hide();
174  removeFocus();
175  fromListBox->lock();
176  fromListBox->remove(item);
177  fromListBox->unlock();
178 
179  FeatItem featItem = item->_feat;
180  _featsTrash.push_back(item);
181  moveFeat(featItem, fromListBox->getTag() == "AvailBox");
182  return;
183  }
184 
185  // For master feat items.
186 
187  // Find feats that belong to the master feat.
188  std::vector<FeatItem> slaveFeatsList;
189  for (std::list<FeatItem>::iterator f = _availFeats.begin(); f != _availFeats.end(); ++f) {
190  if ((*f).masterFeat != item->_feat.featId)
191  continue;
192 
193  slaveFeatsList.push_back(*f);
194  }
195 
196  // Show the popup.
197  std::sort(slaveFeatsList.begin(), slaveFeatsList.end());
198  _featsPopup->setFeats(slaveFeatsList);
199  removeFocus();
200  _featsPopup->show();
201  uint32 returnCode = _featsPopup->run();
202  _featsPopup->hide();
203 
204  if (returnCode == 1)
205  return;
206 
207  GfxMan.lockFrame();
208  fromListBox->lock();
209  fromListBox->remove(item);
210  fromListBox->unlock();
211  _featsTrash.push_back(item);
212 
213  FeatItem chosenFeat = _featsPopup->getChosenFeat();
214  moveFeat(chosenFeat, true);
215  GfxMan.unlockFrame();
216 }
217 
219  if (widget.getTag() == "OkButton") {
220  // Add chosen feats to choices.
221  for (std::vector<WidgetListItem *>::iterator it = _knownListBox->begin(); it != _knownListBox->end(); ++it) {
222  WidgetListItemFeat &featItem = dynamic_cast<WidgetListItemFeat &>(**it);
223  if (!featItem.movable())
224  continue;
225 
226  _choices->setFeat(featItem._feat.featId);
227  }
228 
229  _returnCode = 2;
230  return;
231  }
232 
233  if (widget.getTag() == "CancelButton") {
234  _returnCode = 1;
235  return;
236  }
237 
238  if (widget.getTag() == "ResetButton") {
239  GfxMan.lockFrame();
240  reset();
241  GfxMan.unlockFrame();
242  return;
243  }
244 
245  if (widget.getTag() == "RecommendButton") {
246  GfxMan.lockFrame();
248  GfxMan.unlockFrame();
249  return;
250  }
251 }
252 
254  if (_featsTrash.empty())
255  return;
256 
257  removeFocus();
258  for (std::vector<WidgetListItemFeat *>::iterator f = _featsTrash.begin(); f != _featsTrash.end(); ++f) {
259  (*f)->remove();
260  }
261  _featsTrash.clear();
262 }
263 
265  // Build the list of available feats.
266  _availListBox->lock();
267  _availListBox->clear();
269 
270  const Aurora::TwoDAFile &twodaMasterFeats = TwoDAReg.get2DA("masterfeats");
271 
272  std::list<uint32> masterFeats;
273  for (std::list<FeatItem>::iterator f = _availFeats.begin(); f != _availFeats.end(); ++f) {
274  if (list == 0 && (*f).list > 1)
275  continue;
276 
277  if (list == 2 && (*f).list < 1)
278  continue;
279 
280  FeatItem feat = *f;
281  // Check if the feat belongs to a masterfeat.
282  if (feat.masterFeat < 0xFFFFFFFF) {
283  // Check if the masterfeat is already there.
284  bool found = false;
285  for (std::list<uint32>::iterator mf = masterFeats.begin(); mf != masterFeats.end(); ++mf) {
286  if (feat.masterFeat == *mf) {
287  found = true;
288  break;
289  }
290  }
291 
292  if (found)
293  continue;
294 
295  masterFeats.push_back(feat.masterFeat);
296 
297  const Aurora::TwoDARow &masterFeatRow = twodaMasterFeats.getRow(feat.masterFeat);
298  feat.name = TalkMan.getString(masterFeatRow.getInt("STRREF"));
299  feat.icon = masterFeatRow.getString("ICON");
300  feat.isMasterFeat = true;
301  feat.featId = feat.masterFeat;
302  feat.masterFeat = 0xFFFFFFFF;
303  }
304 
305  WidgetListItemFeat *featItem = new WidgetListItemFeat(*this, feat);
306  _availListBox->add(featItem, true);
307  }
308 
311 }
312 
314  _knownListBox->lock();
315  _knownListBox->clear();
317  std::vector<uint32> feats;
318  _choices->getFeats(feats);
319  for (std::vector<uint32>::iterator f = feats.begin(); f != feats.end(); ++f) {
320  const Aurora::TwoDAFile &twodaFeats = TwoDAReg.get2DA("feat");
321  const Aurora::TwoDARow &featRow = twodaFeats.getRow(*f);
322 
323  FeatItem feat;
324  feat.name = TalkMan.getString(featRow.getInt("FEAT"));
325  feat.icon = featRow.getString("ICON");
326  feat.description = TalkMan.getString(featRow.getInt("DESCRIPTION"));
327  feat.masterFeat = 0xFFFFFFFF;
328  feat.isMasterFeat = false;
329 
330  WidgetListItemFeat *featItem = new WidgetListItemFeat(*this, feat);
331  _knownListBox->add(featItem, true);
332 
333  featItem->changeArrowDirection();
334  featItem->setUnmovable();
335  }
336 
338 
339  for (std::list<FeatItem>::iterator f = _knownFeats.begin(); f != _knownFeats.end(); ++f) {
340  WidgetListItemFeat *featItem = new WidgetListItemFeat(*this, *f);
341  featItem->changeArrowDirection();
342  _knownListBox->add(featItem, true);
343  }
344 
346 }
347 
348 void CharFeats::changeAvailFeats(int8 diff, bool normalFeat, bool rebuild) {
349  if (normalFeat) {
350  _normalFeats += diff;
351  } else {
352  _bonusFeats += diff;
353  }
354 
355  int8 list = 1;
356  if (_bonusFeats == 0 && _hasBonusFeats)
357  list = 0;
358 
359  if (_bonusFeats > 0 && _normalFeats == 0)
360  list = 2;
361 
362  if (rebuild) {
363  size_t startItem = 0;
364  GfxMan.lockFrame();
365  if (_normalFeats + _bonusFeats == 0) {
366  _availListBox->lock();
367  _availListBox->clear();
369  } else {
370  startItem = _availListBox->getStartItem();
371  makeAvailList(list);
372  _availListBox->setStartItem(startItem);
373  }
374 
375  startItem = _knownListBox->getStartItem();
376  makeKnownList();
377  _knownListBox->setStartItem(startItem);
378  GfxMan.unlockFrame();
379  }
380 
381  getLabel("RemainLabel", true)->setText(Common::composeString<uint8>(_normalFeats + _bonusFeats));
382 
383  // Enable/Disable the OK button.
384  if (_normalFeats + _bonusFeats != 0) {
385  getButton("OkButton", true)->setDisabled(true);
386  } else {
387  getButton("OkButton", true)->setDisabled(false);
388  }
389 }
390 
392  // Set list to the initial state.
393  reset();
394 
395  // Retrieve recommended feats.
396  std::vector<uint32> recFeats;
397  _choices->getPrefFeats(recFeats);
398 
399  for (std::vector<uint32>::iterator rF = recFeats.begin(); rF != recFeats.end(); ++rF) {
400  if (_bonusFeats + _normalFeats == 0)
401  break;
402 
403  for (std::list<FeatItem>::iterator aF = _availFeats.begin(); aF != _availFeats.end(); ++aF) {
404  if (*rF != (*aF).featId)
405  continue;
406 
407  // Avoid unnecessary list rebuild.
408  bool rebuild = _bonusFeats + _normalFeats == 1;
409  moveFeat(*aF, true, rebuild);
410  break;
411  }
412  }
413 
414  if (_bonusFeats + _normalFeats != 0)
415  error("Unable to select the recommended feats");
416 }
417 
418 } // End of namespace NWN
419 
420 } // End of namespace Engines
Class to hold the two-dimensional array of a 2DA file.
Definition: 2dafile.h:124
The global graphics manager.
#define TalkMan
Shortcut for accessing the talk manager.
Definition: talkman.h:111
A NWN button widget.
Definition: 2dafile.h:39
const Common::UString & getString(size_t column) const
Return the contents of a cell as a string.
Definition: 2dafile.cpp:59
uint32 _returnCode
The GUI&#39;s return code.
Definition: gui.h:75
Widget * _owner
The widget&#39;s owner, if any.
Definition: widget.h:113
A class holding an UTF-8 string.
Definition: ustring.h:48
WidgetListBox * getListBox(const Common::UString &tag, bool vital=false)
Definition: gui.cpp:318
void makeAvailList(uint8 list)
Definition: charfeats.cpp:264
void remove(WidgetListItem *item)
Definition: listbox.cpp:438
void add(WidgetListItem *item, bool noTag=false)
Definition: listbox.cpp:411
Common::ScopedPtr< CharFeatsPopup > _featsPopup
Definition: charfeats.h:86
UString generateIDNumberString()
Definition: uuid.cpp:65
Common::UString description
uint8_t uint8
Definition: types.h:200
A text object.
void setTag(const Common::UString &tag)
Set the widget&#39;s tag.
void setDisabled(bool disabled)
Disable/Enable the widget.
Definition: button.cpp:107
Feat popup GUI.
Common::UString icon
bool endsWith(const UString &with) const
Definition: ustring.cpp:315
Utility functions for generating unique IDs.
std::list< FeatItem > _availFeats
Definition: charfeats.h:91
void removeFocus()
Forcefully remove the focus from the current widget.
Definition: gui.cpp:422
std::vector< WidgetListItem * >::iterator begin()
Get begin iterator from all the items in WidgetListBox.
Definition: listbox.cpp:654
std::list< FeatItem > _knownFeats
Definition: charfeats.h:92
Utility templates and functions for working with strings and streams.
A NWN listbox widget.
WidgetButton * getButton(const Common::UString &tag, bool vital=false)
Definition: gui.cpp:306
A GUI.
Definition: gui.h:43
WidgetLabel * getLabel(const Common::UString &tag, bool vital=false)
Definition: gui.cpp:270
Common::UString name
WidgetListBox * _availListBox
Definition: charfeats.h:88
Utility templates and functions.
const Common::UString & getTag() const
Get the widget&#39;s tag.
Definition: widget.cpp:45
void setMode(Mode mode)
Definition: listbox.cpp:313
void getPrefFeats(std::vector< uint32 > &feats)
CharGenChoices * _choices
Definition: chargenbase.h:45
Handling BioWare&#39;s 2DAs (two-dimensional array).
void subActive(Widget &widget)
A sub-widget was activated.
Definition: charfeats.cpp:70
The feats selection GUI.
CharFeats(CharGenChoices &choices, ::Engines::Console *console=0)
Definition: charfeats.cpp:77
WidgetListItemFeat(::Engines::GUI &gui, FeatItem &feat)
Definition: charfeats.cpp:51
void load(const Common::UString &resref)
Definition: gui.cpp:77
std::vector< WidgetListItem * >::iterator end()
Get end iterator from all the items in WidgetListBox.
Definition: listbox.cpp:658
#define TwoDAReg
Shortcut for accessing the 2da registry.
Definition: 2dareg.h:101
A NWN listbox widget.
Definition: listbox.h:116
Common::ScopedPtr< CharHelp > _featHelp
Definition: charfeats.h:85
The global 2DA registry.
int32 getInt(size_t column) const
Return the contents of a cell as an int.
Definition: 2dafile.cpp:75
void getFeatItems(std::list< FeatItem > &feats, uint8 &normalFeats, uint8 &bonusFeats)
void moveFeat(FeatItem feat, bool toKnownFeats, bool rebuild=true)
Definition: charfeats.cpp:131
const TwoDARow & getRow(size_t row) const
Get a row.
Definition: 2dafile.cpp:421
Common::ScopedPtr< Graphics::Aurora::Text > _text
Help popup GUI.
A widget in a GUI.
Definition: widget.h:40
int8_t int8
Definition: types.h:199
uint32_t uint32
Definition: types.h:204
The global talk manager for Aurora strings.
A creature in a Neverwinter Nights area.
void fixWidgetType(const Common::UString &tag, NWN::GUI::WidgetType &type)
Definition: charfeats.cpp:118
size_t getStartItem() const
Get the first item shown in the list.
Definition: listbox.cpp:650
void callbackRun()
Callback that&#39;s triggered periodically in the run() method.
Definition: charfeats.cpp:253
WidgetListBox * _knownListBox
Definition: charfeats.h:89
A row within a 2DA file.
Definition: 2dafile.h:61
void NORETURN_PRE error(const char *s,...)
Definition: util.cpp:86
uint8 list
The kind of list the feat belongs to: 0 (general feat), 2 (bonus feat), 1 (both)
std::vector< WidgetListItemFeat * > _featsTrash
Definition: charfeats.h:94
void setStartItem(size_t firstItem)
Set the first item to show in the list.
Definition: listbox.cpp:643
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
A NWN label widget.
void showFeatHelp(FeatItem &feat)
Definition: charfeats.cpp:123
void getFeats(std::vector< uint32 > &feats)
void setText(const Common::UString &text)
Definition: label.cpp:67
void changeAvailFeats(int8 diff, bool normalFeat, bool rebuild=true)
Definition: charfeats.cpp:348
void callbackActive(Widget &widget)
Callback that&#39;s triggered when a widget was activated.
Definition: charfeats.cpp:218