xoreos  0.0.5
nwn.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 <cassert>
26 
27 #include "src/common/util.h"
28 #include "src/common/filelist.h"
29 #include "src/common/filepath.h"
30 #include "src/common/configman.h"
31 
32 #include "src/aurora/util.h"
33 #include "src/aurora/resman.h"
34 #include "src/aurora/language.h"
35 #include "src/aurora/talkman.h"
37 
38 #include "src/events/events.h"
39 
43 
49 
50 #include "src/engines/nwn/nwn.h"
54 #include "src/engines/nwn/game.h"
55 
56 namespace Engines {
57 
58 namespace NWN {
59 
61  _hasXP1(false), _hasXP2(false), _hasXP3(false) {
62 
63  _console.reset(new Console(*this));
64 }
65 
67 }
68 
70  Aurora::Platform UNUSED(platform),
71  std::vector<Aurora::Language> &languages) const {
72  try {
73  Common::FileList files;
74  if (!files.addDirectory(target))
75  return true;
76 
77  Common::UString tlk = files.findFirst("dialog.tlk", true);
78  if (tlk.empty())
79  return true;
80 
82  if (languageID == Aurora::kLanguageInvalid)
83  return true;
84 
85  Aurora::Language language = LangMan.getLanguage(languageID);
86  if (language == Aurora::kLanguageInvalid)
87  return true;
88 
89  languages.push_back(language);
90 
91  } catch (...) {
92  }
93 
94  return true;
95 }
96 
98  language = _language;
99  return true;
100 }
101 
103  Aurora::Language language;
104  if (!evaluateLanguage(false, language) || (_language != language))
105  return false;
106 
107  return true;
108 }
109 
111  assert(_game);
112 
113  return *_game;
114 }
115 
117  init();
118  if (EventMan.quitRequested())
119  return;
120 
121  CursorMan.hideCursor();
122  CursorMan.set();
123 
124  playIntroVideos();
125  if (EventMan.quitRequested())
126  return;
127 
128  CursorMan.showCursor();
129 
130  _game.reset(new Game(*this, *_console, *_version));
131  _game->run();
132 
133  deinit();
134 }
135 
137  LoadProgress progress(20);
138 
139  progress.step("Declare languages");
141 
142  progress.step("Detecting game version");
143  detectVersion();
144 
145  if (evaluateLanguage(true, _language))
146  status("Setting the language to %s", LangMan.getLanguageName(_language).c_str());
147  else
148  warning("Failed to detect this game's language");
149 
150  LangMan.setCurrentLanguage(_language);
151 
152  progress.step("Loading user game config");
153  initConfig();
154  checkConfig();
155 
156  if (EventMan.quitRequested())
157  return;
158 
159  initResources(progress);
160 
161  if (EventMan.quitRequested())
162  return;
163 
164  progress.step("Loading game cursors");
165  initCursors();
166 
167  if (EventMan.quitRequested())
168  return;
169 
170  progress.step("Initializing internal game config");
171  initGameConfig();
172 
173  progress.step("Successfully initialized the engine");
174 }
175 
177  _version.reset(new Version(_platform));
178 
179  if (_version->detect(_target)) {
180  status("This is Neverwinter Nights %s v%s",
181  _version->getPlatformName().c_str(), _version->getVersionString().c_str());
182 
183  if (_version->isTooOld()) {
184  warning("Your version of Neverwinter Nights is too old");
185  warning("Please update to v%s for optimal support", _version->getOptimumVersionString().c_str());
186  } else if (_version->isTooNew()) {
187  warning("Your version of Neverwinter Nights is too new!?");
188  warning("Please contact us with detailed information about your version");
189  }
190 
191  } else {
192  warning("Failed to detect the patch version of your Neverwinter Nights installation");
193  }
194 }
195 
197  static const Aurora::LanguageManager::Declaration kLanguageDeclarations[] = {
208  };
209 
210  LangMan.addLanguages(kLanguageDeclarations, ARRAYSIZE(kLanguageDeclarations));
211 }
212 
214  progress.step("Setting base directory");
215  ResMan.registerDataBase(_target);
216 
217  progress.step("Adding extra archive directories");
218  indexMandatoryDirectory("data" , 0, 0, 2);
219  indexMandatoryDirectory("nwm" , 0, 0, 3);
220  indexMandatoryDirectory("modules" , 0, 0, 4);
221  indexMandatoryDirectory("hak" , 0, 0, 5);
222  indexMandatoryDirectory("texturepacks", 0, 0, 6);
223 
224  progress.step("Loading main KEY");
225  indexMandatoryArchive("chitin.key", 10);
226 
227  progress.step("Loading expansions and patch KEYs");
228 
229  // Base game patch
230  indexOptionalArchive("patch.key", 11);
231 
232  // Expansion 1: Shadows of Undrentide (SoU)
233  _hasXP1 = ResMan.hasArchive("xp1.key");
234  indexOptionalArchive("xp1.key" , 12);
235  indexOptionalArchive("xp1patch.key", 13);
236 
237  // Expansion 2: Hordes of the Underdark (HotU)
238  _hasXP2 = ResMan.hasArchive("xp2.key");
239  indexOptionalArchive("xp2.key" , 14);
240  indexOptionalArchive("xp2patch.key", 15);
241 
242  // Expansion 3: Kingmaker (resources also included in the final 1.69 patch)
243  _hasXP3 = ResMan.hasArchive("xp3.key");
244  indexOptionalArchive("xp3.key" , 16);
245  indexOptionalArchive("xp3patch.key", 17);
246 
247  progress.step("Loading GUI textures");
248  indexMandatoryArchive("gui_32bit.erf", 50);
249  indexOptionalArchive ("xp1_gui.erf" , 51);
250  indexOptionalArchive ("xp2_gui.erf" , 52);
251 
252  progress.step("Indexing extra sound resources");
253  indexMandatoryDirectory("ambient" , 0, 0, 100);
254  progress.step("Indexing extra music resources");
255  indexMandatoryDirectory("music" , 0, 0, 101);
256  progress.step("Indexing extra movie resources");
257  indexMandatoryDirectory("movies" , 0, 0, 102);
258  progress.step("Indexing extra image resources");
259  indexOptionalDirectory ("portraits" , 0, 0, 103);
260  progress.step("Indexing extra talktables");
261  indexOptionalDirectory ("tlk" , 0, 0, 105);
262  progress.step("Indexing databases");
263  indexOptionalDirectory ("database" , 0, 0, 106);
264 
265  // Texture packs at 400-403, in module.cpp
266 
267  progress.step("Indexing override files");
268  indexOptionalDirectory("override", 0, 0, 500);
269 
270  if (EventMan.quitRequested())
271  return;
272 
273  progress.step("Loading main talk table");
274  TalkMan.addTable("dialog", "dialogf", false, 0);
275 
276  progress.step("Registering file formats");
279 
280  // Blacklist the DDS version of the galahad14 font, because in versions of NWN coming
281  // with a Cyrillic one, the DDS file is still Latin.
282  ResMan.blacklist("fnt_galahad14", Aurora::kFileTypeDDS);
283 
285 }
286 
288  static const char * const kBogusTextures[] = {
289  "belt_g",
290  "FB1_g",
291  "head_g",
292  "Lbicep_g",
293  "lbicep_g",
294  "lfoot_g",
295  "lforearm_g",
296  "lhand_g",
297  "lshin_g",
298  "Lshoulder_g",
299  "lshoulder_g",
300  "lthigh_g",
301  "Material",
302  "neck_g",
303  "pelvis_g",
304  "pmh0_head001g",
305  "Rbicep_g",
306  "rbicep_g",
307  "rfoot_g",
308  "rforearm_g",
309  "rhand_g",
310  "rshin_g",
311  "Rshoulder_g",
312  "rshoulder_g",
313  "rthigh_g",
314  "TF3_g",
315  "torso_g"
316  };
317 
318  for (size_t i = 0; i < ARRAYSIZE(kBogusTextures); i++)
319  TextureMan.addBogusTexture(kBogusTextures[i]);
320 }
321 
323  CursorMan.add("gui_mp_defaultd" , "default", "down");
324  CursorMan.add("gui_mp_defaultu" , "default", "up" );
325 
326  CursorMan.add("gui_mp_actiond" , "action" , "down");
327  CursorMan.add("gui_mp_actionu" , "action" , "up" );
328  CursorMan.add("gui_mp_attackd" , "attack" , "down");
329  CursorMan.add("gui_mp_attacku" , "attack" , "up" );
330  CursorMan.add("gui_mp_created" , "create" , "down");
331  CursorMan.add("gui_mp_createu" , "create" , "up" );
332  CursorMan.add("gui_mp_disarmd" , "disarm" , "down");
333  CursorMan.add("gui_mp_disarmu" , "disarm" , "up" );
334  CursorMan.add("gui_mp_doord" , "door" , "down");
335  CursorMan.add("gui_mp_dooru" , "door" , "up" );
336  CursorMan.add("gui_mp_examined" , "examine" , "down");
337  CursorMan.add("gui_mp_examineu" , "examine" , "up" );
338  CursorMan.add("gui_mp_followd" , "follow" , "down");
339  CursorMan.add("gui_mp_followu" , "follow" , "up" );
340  CursorMan.add("gui_mp_heald" , "heal" , "down");
341  CursorMan.add("gui_mp_healu" , "heal" , "up" );
342  CursorMan.add("gui_mp_killd" , "kill" , "down");
343  CursorMan.add("gui_mp_killu" , "kill" , "up" );
344  CursorMan.add("gui_mp_lockd" , "lock" , "down");
345  CursorMan.add("gui_mp_locku" , "lock" , "up" );
346  CursorMan.add("gui_mp_magicd" , "magic" , "down");
347  CursorMan.add("gui_mp_magicu" , "magic" , "up" );
348  CursorMan.add("gui_mp_pickupd" , "pickup" , "down");
349  CursorMan.add("gui_mp_pickupu" , "pickup" , "up" );
350  CursorMan.add("gui_mp_pushpind" , "pushpin" , "down");
351  CursorMan.add("gui_mp_pushpinu" , "pushpin" , "up" );
352  CursorMan.add("gui_mp_talkd" , "talk" , "down");
353  CursorMan.add("gui_mp_talku" , "talk" , "up" );
354  CursorMan.add("gui_mp_transd" , "trans" , "down");
355  CursorMan.add("gui_mp_transu" , "trans" , "up" );
356  CursorMan.add("gui_mp_used" , "use" , "down");
357  CursorMan.add("gui_mp_useu" , "use" , "up" );
358  CursorMan.add("gui_mp_walkd" , "walk" , "down");
359  CursorMan.add("gui_mp_walku" , "walk" , "up" );
360 
361  CursorMan.add("gui_mp_noactiond", "noaction" , "down");
362  CursorMan.add("gui_mp_noactionu", "noaction" , "up" );
363  CursorMan.add("gui_mp_noatckd" , "noattack" , "down");
364  CursorMan.add("gui_mp_noatcku" , "noattack" , "up" );
365  CursorMan.add("gui_mp_nocreatd" , "nocreate" , "down");
366  CursorMan.add("gui_mp_nocreatu" , "nocreate" , "up" );
367  CursorMan.add("gui_mp_nodisarmd", "nodisarm" , "down");
368  CursorMan.add("gui_mp_nodisarmu", "nodisarm" , "up" );
369  CursorMan.add("gui_mp_noexamd" , "noexamine", "down");
370  CursorMan.add("gui_mp_noexamu" , "noexamine", "up" );
371  CursorMan.add("gui_mp_noheald" , "noheal" , "down");
372  CursorMan.add("gui_mp_nohealu" , "noheal" , "up" );
373  CursorMan.add("gui_mp_nokilld" , "nokill" , "down");
374  CursorMan.add("gui_mp_nokillu" , "nokill" , "up" );
375  CursorMan.add("gui_mp_nolockd" , "nolock" , "down");
376  CursorMan.add("gui_mp_nolocku" , "nolock" , "up" );
377  CursorMan.add("gui_mp_nomagicd" , "nomagic" , "down");
378  CursorMan.add("gui_mp_nomagicu" , "nomagic" , "up" );
379  CursorMan.add("gui_mp_notalkd" , "notalk" , "down");
380  CursorMan.add("gui_mp_notalku" , "notalk" , "up" );
381  CursorMan.add("gui_mp_noused" , "nouse" , "down");
382  CursorMan.add("gui_mp_nouseu" , "nouse" , "up" );
383  CursorMan.add("gui_mp_nowalkd" , "nowalk" , "down");
384  CursorMan.add("gui_mp_nowalku" , "nowalk" , "up" );
385 
386  CursorMan.add("gui_mp_arwalk00", "arrowwalk", "N");
387  CursorMan.add("gui_mp_arwalk01", "arrowwalk", "NNE");
388  CursorMan.add("gui_mp_arwalk02", "arrowwalk", "NE");
389  CursorMan.add("gui_mp_arwalk03", "arrowwalk", "ENE");
390  CursorMan.add("gui_mp_arwalk04", "arrowwalk", "E");
391  CursorMan.add("gui_mp_arwalk05", "arrowwalk", "ESE");
392  CursorMan.add("gui_mp_arwalk06", "arrowwalk", "SE");
393  CursorMan.add("gui_mp_arwalk07", "arrowwalk", "SSE");
394  CursorMan.add("gui_mp_arwalk08", "arrowwalk", "S");
395  CursorMan.add("gui_mp_arwalk09", "arrowwalk", "SSW");
396  CursorMan.add("gui_mp_arwalk10", "arrowwalk", "SW");
397  CursorMan.add("gui_mp_arwalk11", "arrowwalk", "WSW");
398  CursorMan.add("gui_mp_arwalk12", "arrowwalk", "W");
399  CursorMan.add("gui_mp_arwalk13", "arrowwalk", "WNW");
400  CursorMan.add("gui_mp_arwalk14", "arrowwalk", "NW");
401  CursorMan.add("gui_mp_arwalk15", "arrowwalk", "NNW");
402 
403  CursorMan.add("gui_mp_arrun00", "arrowrun", "N");
404  CursorMan.add("gui_mp_arrun01", "arrowrun", "NNE");
405  CursorMan.add("gui_mp_arrun02", "arrowrun", "NE");
406  CursorMan.add("gui_mp_arrun03", "arrowrun", "ENE");
407  CursorMan.add("gui_mp_arrun04", "arrowrun", "E");
408  CursorMan.add("gui_mp_arrun05", "arrowrun", "ESE");
409  CursorMan.add("gui_mp_arrun06", "arrowrun", "SE");
410  CursorMan.add("gui_mp_arrun07", "arrowrun", "SSE");
411  CursorMan.add("gui_mp_arrun08", "arrowrun", "S");
412  CursorMan.add("gui_mp_arrun09", "arrowrun", "SSW");
413  CursorMan.add("gui_mp_arrun10", "arrowrun", "SW");
414  CursorMan.add("gui_mp_arrun11", "arrowrun", "WSW");
415  CursorMan.add("gui_mp_arrun12", "arrowrun", "W");
416  CursorMan.add("gui_mp_arrun13", "arrowrun", "WNW");
417  CursorMan.add("gui_mp_arrun14", "arrowrun", "NW");
418  CursorMan.add("gui_mp_arrun15", "arrowrun", "NNW");
419 
420  CursorMan.setDefault("default", "up");
421 }
422 
424  ConfigMan.setInt(Common::kConfigRealmDefault, "menufogcount" , 4);
425  ConfigMan.setInt(Common::kConfigRealmDefault, "texturepack" , 1);
426  ConfigMan.setInt(Common::kConfigRealmDefault, "difficulty" , 0);
427  ConfigMan.setInt(Common::kConfigRealmDefault, "feedbackmode" , 2);
428  ConfigMan.setInt(Common::kConfigRealmDefault, "tooltipdelay" , 100);
429 
430  ConfigMan.setBool(Common::kConfigRealmDefault, "largefonts" , false);
431  ConfigMan.setBool(Common::kConfigRealmDefault, "mouseoverfeedback", true);
432 }
433 
435  ConfigMan.setBool(Common::kConfigRealmGameTemp, "NWN_hasXP1", _hasXP1);
436  ConfigMan.setBool(Common::kConfigRealmGameTemp, "NWN_hasXP2", _hasXP2);
437  ConfigMan.setBool(Common::kConfigRealmGameTemp, "NWN_hasXP3", _hasXP3);
438 
439  ConfigMan.setString(Common::kConfigRealmGameTemp, "NWN_extraModuleDir",
440  Common::FilePath::findSubDirectory(_target, "modules", true));
441  ConfigMan.setString(Common::kConfigRealmGameTemp, "NWN_campaignDir",
443  ConfigMan.setString(Common::kConfigRealmGameTemp, "NWN_localPCDir",
444  Common::FilePath::findSubDirectory(_target, "localvault", true));
445  ConfigMan.setString(Common::kConfigRealmGameTemp, "NWN_serverPCDir",
446  Common::FilePath::findSubDirectory(_target, "servervault", true));
447 
448  TokenMan.set("<StartCheck>" , "<cFF0000FF>");
449  TokenMan.set("<StartAction>" , "<c00FF00FF>");
450  TokenMan.set("<StartHighlight>", "<c0000FFFF>");
451  TokenMan.set("</Start>" , "</c>");
452 
453  // TODO: <PlayerName>
454 }
455 
457  checkConfigInt("menufogcount" , 0, 5);
458  checkConfigInt("texturepack" , 0, 3);
459  checkConfigInt("difficulty" , 0, 3);
460  checkConfigInt("feedbackmode" , 0, 2);
461  checkConfigInt("tooltipdelay" , 100, 2700);
462 }
463 
466 
467  _version.reset();
468  _game.reset();
469 }
470 
472  playVideo("atarilogo");
473  playVideo("biowarelogo");
474  playVideo("wotclogo");
475  playVideo("fge_logo_black");
476  playVideo("nwnintro");
477 }
478 
479 } // End of namespace NWN
480 
481 } // End of namespace Engines
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
Aurora::Platform _platform
Definition: engine.h:84
bool getLanguage(Aurora::Language &language) const
Return the game&#39;s current language.
Definition: nwn.cpp:97
void playVideo(const Common::UString &video)
Play this video resource.
Definition: util.cpp:54
GameID
Definition: types.h:393
Generic Aurora engines resource utility functions.
#define TalkMan
Shortcut for accessing the talk manager.
Definition: talkman.h:111
Engine class handling Neverwinter Nights.
A class holding an UTF-8 string.
Definition: ustring.h:48
Temporary game settings/properties.
Definition: configman.h:47
#define TextureMan
Shortcut for accessing the texture manager.
Definition: textureman.h:127
Common::ScopedPtr< Game > _game
Definition: nwn.h:74
The global config manager.
Common::ScopedPtr< Console > _console
Definition: engine.h:87
bool indexOptionalArchive(const Common::UString &file, uint32 priority, const std::vector< byte > &password, Common::ChangeID *changeID)
Definition: resources.cpp:69
The Aurora texture manager.
bool evaluateLanguage(bool find, Aurora::Language &language) const
Definition: engine.cpp:198
Game & getGame()
Return the context running the actual game.
Definition: nwn.cpp:110
Utility functions to handle files used in BioWare&#39;s Aurora engine.
#define ARRAYSIZE(x)
Macro which determines the number of entries in a fixed size array.
Definition: util.h:131
Neverwinter Nights installation version detection.
Language
Definition: language.h:46
Aurora::Language _language
Definition: nwn.h:68
bool indexOptionalDirectory(const Common::UString &dir, const char *glob, int depth, uint32 priority, Common::ChangeID *changeID)
Add a directory to the resource manager, if it exists.
Definition: resources.cpp:133
void declareBogusTextures()
Definition: nwn.cpp:287
The Aurora font manager.
UString findFirst(const UString &str, bool caseInsensitive) const
Find the first file ending with the given string.
Definition: filelist.cpp:193
void indexMandatoryArchive(const Common::UString &file, uint32 priority, const std::vector< byte > &password, Common::ChangeID *changeID)
Definition: resources.cpp:36
Neverwinter Nights (debug) console.
Neverwinter Nights model loader.
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
#define UNUSED(x)
Definition: system.h:170
Windows codepage 950 (Traditional Chinese, similar to Big5).
Definition: encoding.h:56
Utility templates and functions.
void initResources(LoadProgress &progress)
Definition: nwn.cpp:213
void unregisterModelLoader()
Definition: model.cpp:41
The global events manager.
Types and functions related to language.
bool changeLanguage()
Change the game&#39;s current language.
Definition: nwn.cpp:102
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
bool detectLanguages(Aurora::GameID game, const Common::UString &target, Aurora::Platform platform, std::vector< Aurora::Language > &languages) const
Detect which languages this game instance supports.
Definition: nwn.cpp:69
Handling BioWare&#39;s TLK talk tables.
void warning(const char *s,...)
Definition: util.cpp:33
#define CursorMan
Shortcut for accessing the cursor manager.
Definition: cursorman.h:129
#define EventMan
Shortcut for accessing the events manager.
Definition: events.h:210
The Aurora cursor manager.
Displaying the progress in loading a game.
Textured font, used by NWN and KotOR/KotOR2.
Definition: fontman.h:47
Common::ScopedPtr< Version > _version
Definition: nwn.h:66
void indexMandatoryDirectory(const Common::UString &dir, const char *glob, int depth, uint32 priority, Common::ChangeID *changeID)
Add a directory to the resource manager, erroring out if it does not exist.
Definition: resources.cpp:112
void run()
Run the game.
Definition: nwn.cpp:116
Common::UString _target
Definition: engine.h:85
void registerModelLoader(ModelLoader *loader)
Definition: model.cpp:37
Application or game defaults.
Definition: configman.h:46
void playIntroVideos()
Definition: nwn.cpp:471
#define LangMan
Shortcut for accessing the language manager.
Definition: language.h:275
Windows codepage 932 (Japanese, extended Shift-JIS).
Definition: encoding.h:53
uint32_t uint32
Definition: types.h:204
The global talk manager for Aurora strings.
A list of files.
Definition: filelist.h:35
void step(const Common::UString &description)
Take a step in advancing the progress.
void status(const char *s,...)
Definition: util.cpp:52
void checkConfigInt(const Common::UString &key, int min, int max)
Make sure that an int config value is in the right range.
Definition: util.cpp:116
Windows codepage 1250 (Eastern European, Latin alphabet).
Definition: encoding.h:49
bool addDirectory(const UString &directory, int recurseDepth=0)
Add a directory to the list.
Definition: filelist.cpp:102
Generic Aurora engines utility functions.
A list of files.
The context handling the gameplay in Neverwinter Nights.
Windows codepage 1252 (Western European, Latin alphabet).
Definition: encoding.h:51
Manager for tokens in Aurora engines text strings.
Windows codepage 949 (Korean, similar to EUC-KR).
Definition: encoding.h:55
uint32 getLanguageID() const
Return the language ID (ungendered) of the talk table.
void declareLanguages()
Definition: nwn.cpp:196
Windows codepage 936 (Simplified Chinese, extended GB2312 with GBK codepoints).
Definition: encoding.h:54
Platform
Definition: types.h:429
#define TokenMan
Shortcut for accessing the token manager.
Definition: tokenman.h:63
Texture, DirectDraw Surface.
Definition: types.h:98
The global resource manager for Aurora resources.
Utility class for manipulating file paths.
#define FontMan
Shortcut for accessing the font manager.
Definition: fontman.h:105
static UString findSubDirectory(const UString &directory, const UString &subDirectory, bool caseInsensitive=false)
Find a directory&#39;s subdirectory.
Definition: filepath.cpp:318
Generic Aurora engines model functions.