xoreos  0.0.5
campaign.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 "src/common/util.h"
26 #include "src/common/error.h"
27 #include "src/common/configman.h"
28 #include "src/common/readfile.h"
29 #include "src/common/filepath.h"
30 #include "src/common/filelist.h"
31 
32 #include "src/aurora/resman.h"
33 #include "src/aurora/gff3file.h"
34 
35 #include "src/graphics/camera.h"
36 
37 #include "src/events/events.h"
38 
41 
45 
46 namespace Engines {
47 
48 namespace Witcher {
49 
50 Campaign::Campaign(::Engines::Console &console) : _console(&console),
51  _hasCampaign(false), _running(false), _exit(true), _newCampaignStandalone(false) {
52 
53  _module.reset(new Module(*_console));
54 }
55 
57  try {
58  clear();
59  } catch (...) {
60  }
61 }
62 
64  unload(true);
65 }
66 
68  return _name;
69 }
70 
72  return _description;
73 }
74 
76  assert(_module);
77 
78  return *_module;
79 }
80 
81 bool Campaign::isLoaded() const {
82  return _hasCampaign && _module->isLoaded() && _pc;
83 }
84 
85 bool Campaign::isRunning() const {
86  return !EventMan.quitRequested() && _running && !_exit && _module->isRunning();
87 }
88 
89 void Campaign::unload(bool completeUnload) {
90  _module->clear();
91 
92  _hasCampaign = false;
93  _running = false;
94  _exit = true;
95 
96  _name.clear();
98 
99  _modules.clear();
101 
103  _newCampaignStandalone = false;
104 
105  _eventQueue.clear();
106 
107  if (completeUnload)
108  unloadPC();
109 }
110 
112  _pc.reset();
113 }
114 
115 void Campaign::load(const Common::UString &campaign) {
116  if (isRunning()) {
117  // We are currently running a campaign. Schedule a safe change instead
118 
119  changeCampaign(campaign, false);
120  return;
121  }
122 
123  // We are not currently running a campaign. Directly load the new campaign
124  loadCampaign(campaign, false);
125 }
126 
128  if (isRunning()) {
129  // We are currently running a campaign. Schedule a safe change instead
130 
131  changeCampaign(module, true);
132  return;
133  }
134 
135  // We are not currently running a campaign. Directly load the new campaign
136  loadCampaign(module, true);
137 }
138 
140  const Common::FileList mmdFiles(ConfigMan.getString("WITCHER_moduleDir"), -1);
141 
142  for (Common::FileList::const_iterator c = mmdFiles.begin(); c != mmdFiles.end(); ++c) {
143  if (!Common::FilePath::getFile(*c).equalsIgnoreCase(campaign + ".mmd"))
144  continue;
145 
146  return new Common::ReadFile(*c);
147  }
148 
149  throw Common::Exception("No such campaign \"%s\"", campaign.c_str());
150 }
151 
153  const Common::FileList mmdFiles(ConfigMan.getString("WITCHER_moduleDir"), -1);
154 
155  for (Common::FileList::const_iterator c = mmdFiles.begin(); c != mmdFiles.end(); ++c) {
156  if (!Common::FilePath::getFile(*c).equalsIgnoreCase(campaign + ".mmd"))
157  continue;
158 
160  }
161 
162  throw Common::Exception("No such campaign \"%s\"", campaign.c_str());
163 }
164 
166  try {
167  Aurora::GFF3File mmd(openMMD(campaign), MKTAG('M', 'M', 'D', ' '));
168 
169  mmd.getTopLevel().getLocString("Meta_Name", _name);
170  mmd.getTopLevel().getLocString("Meta_Desc", _description);
171 
172  _startModule = mmd.getTopLevel().getString("StartingMod");
173  if (_startModule.empty())
174  throw Common::Exception("No starting module");
175 
176  const Aurora::GFF3List &modules = mmd.getTopLevel().getList("Meta_Mod_list");
177  for (Aurora::GFF3List::const_iterator m = modules.begin(); m != modules.end(); ++m)
178  _modules.push_back((*m)->getString("Mod_Name"));
179 
180  _startModule = getDirectory(campaign) + "/" + _startModule + ".mod";
181 
182  } catch (Common::Exception &e) {
183  e.add("Failed to load campaign \"%s\" (\"%s\")", campaign.c_str(), _description.getString().c_str());
184 
185  throw;
186  }
187 }
188 
190  const Common::UString mod = Module::findModule(module, true);
191  if (mod.empty())
192  throw Common::Exception("No such module \"%s\"", module.c_str());
193 
194  _modules.push_back(mod);
195  _startModule = mod;
196 }
197 
198 void Campaign::loadCampaign(const Common::UString &campaign, bool standalone) {
199  unload(false);
200 
201  if (!standalone)
202  loadCampaignFile(campaign);
203  else
204  setupStandaloneModule(campaign);
205 
206  try {
207  _module->load(_startModule);
208  } catch (Common::Exception &e) {
209  clear();
210 
211  e.add("Failed to load campaign's starting module");
212  throw;
213  }
214 
215  _hasCampaign = true;
216 }
217 
219  unloadPC();
220 
221  if (utc.empty())
222  throw Common::Exception("Tried to load an empty PC");
223 
224  try {
225  _pc.reset(new Creature(utc));
226  } catch (Common::Exception &e) {
227  e.add("Can't load PC \"%s\"", utc.c_str());
228  throw e;
229  }
230 }
231 
233  _exit = true;
234 }
235 
237  if (!_hasCampaign)
238  throw Common::Exception("Campaign::enter(): Lacking a campaign?!?");
239 
240  if (!_pc)
241  throw Common::Exception("Campaign::enter(): Lacking a PC?!?");
242 
243  _pc->clearVariables();
244  _module->enter(*_pc);
245 
246  _running = true;
247  _exit = false;
248 }
249 
251  _module->leave();
252 
253  _running = false;
254  _exit = true;
255 }
256 
257 void Campaign::addEvent(const Events::Event &event) {
258  _eventQueue.push_back(event);
259 }
260 
262  if (!isRunning())
263  return;
264 
265  replaceCampaign();
266 
267  if (!isRunning())
268  return;
269 
270  handleEvents();
271 }
272 
274  for (EventQueue::const_iterator event = _eventQueue.begin(); event != _eventQueue.end(); ++event) {
275  // Handle console
276  if (_console->isVisible()) {
277  _console->processEvent(*event);
278  continue;
279  }
280 
281  if (event->type == Events::kEventKeyDown) {
282  // Console
283  if ((event->key.keysym.sym == SDLK_d) && (event->key.keysym.mod & KMOD_CTRL)) {
284  _console->show();
285  continue;
286  }
287  }
288 
289  // Camera
290  if (FreeRoamCam.handleCameraInput(*event))
291  continue;
292 
293  _module->addEvent(*event);
294  }
295 
296  _eventQueue.clear();
297 
298  CameraMan.update();
299 
300  _module->processEventQueue();
301 }
302 
303 void Campaign::changeCampaign(const Common::UString &campaign, bool standalone) {
304  _newCampaign = campaign;
305  _newCampaignStandalone = standalone;
306 }
307 
309  if (_newCampaign.empty())
310  return;
311 
312  const Common::UString campaign = _newCampaign;
313  const bool standalone = _newCampaignStandalone;
314 
315  loadCampaign(campaign, standalone);
316  enter();
317 }
318 
320  _module->refreshLocalized();
321 }
322 
324  try {
325  Aurora::GFF3File mmd(openMMD(campaign), MKTAG('M', 'M', 'D', ' '));
326 
327  return mmd.getTopLevel().getString("Meta_Name");
328 
329  } catch (...) {
330  }
331 
332  return "";
333 }
334 
336  try {
337  Aurora::GFF3File mmd(openMMD(campaign), MKTAG('M', 'M', 'D', ' '));
338 
339  return mmd.getTopLevel().getString("Meta_Desc");
340 
341  } catch (...) {
342  }
343 
344  return "";
345 }
346 
347 } // End of namespace Witcher
348 
349 } // End of namespace Engines
void load(const Common::UString &campaign)
Load a campaign.
Definition: campaign.cpp:115
The context holding a The Witcher campaign.
Handling version V3.2/V3.3 of BioWare&#39;s GFFs (generic file format).
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
void changeCampaign(const Common::UString &campaign, bool standalone)
Schedule a change to a new campaign.
Definition: campaign.cpp:303
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
bool isVisible() const
Definition: console.cpp:797
Aurora::LocString _name
The name of the currently loaded campaign.
Definition: campaign.h:119
Common::UString _startModule
The module the current campaign starts in.
Definition: campaign.h:126
bool getLocString(const Common::UString &field, LocString &str) const
Definition: gff3file.cpp:614
::Engines::Console * _console
Definition: campaign.h:112
A class holding an UTF-8 string.
Definition: ustring.h:48
const Aurora::LocString & getName() const
Return the name of the current campaign.
Definition: campaign.cpp:67
A localized string.
Definition: locstring.h:43
The global config manager.
bool _exit
Should we exit the campaign?
Definition: campaign.h:116
bool isLoaded() const
Is a campaign currently loaded and ready to run?
Definition: campaign.cpp:81
void exit()
Exit the currently running campaign.
Definition: campaign.cpp:232
void addEvent(const Events::Event &event)
Add a single event for consideration into the event queue.
Definition: campaign.cpp:257
void processEventQueue()
Process the current event queue.
Definition: campaign.cpp:261
Camera management.
bool equalsIgnoreCase(const UString &str) const
Definition: ustring.cpp:218
A simple streaming file reading class.
Definition: readfile.h:40
void clear()
Clear the whole context.
Definition: campaign.cpp:63
std::list< UString >::const_iterator const_iterator
Definition: filelist.h:37
const GFF3Struct & getTopLevel() const
Returns the top-level struct.
Definition: gff3file.cpp:91
const Common::UString & getString(Language language, LanguageGender gender=kLanguageGenderCurrent) const
Get the string of that language.
Definition: locstring.cpp:82
Exception that provides a stack of explanations.
Definition: error.h:36
#define FreeRoamCam
SDL_Event Event
Definition: types.h:42
void loadCampaign(const Common::UString &campaign, bool standalone)
Load a new campaign.
Definition: campaign.cpp:198
const Aurora::LocString & getDescription() const
Return the description of the current campaign.
Definition: campaign.cpp:71
void loadCampaignFile(const Common::UString &campaign)
Load the actual campaign resources.
Definition: campaign.cpp:165
Keyboard key was pressed.
Definition: types.h:46
Module & getModule()
Return the currently running module.
Definition: campaign.cpp:75
Basic exceptions to throw.
A creature in a The Witcher area.
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
bool _running
Are we currently running a campaign?
Definition: campaign.h:115
void refreshLocalized()
Refresh all localized strings.
Definition: campaign.cpp:319
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
Utility templates and functions.
Common::ScopedPtr< Module > _module
The current module of the current campaign.
Definition: campaign.h:129
The global events manager.
A GFF (generic file format) V3.2/V3.3 file, found in all Aurora games except Sonic Chronicles: The Da...
Definition: gff3file.h:85
void enter()
Enter the loaded campaign, starting it.
Definition: campaign.cpp:236
void setupStandaloneModule(const Common::UString &module)
Set up the loading of a singular, stand-alone module.
Definition: campaign.cpp:189
static Common::SeekableReadStream * openMMD(const Common::UString &campaign)
Open the MMD campaign file for this campaign.
Definition: campaign.cpp:139
Common::ScopedPtr< Creature > _pc
The player character we use.
Definition: campaign.h:132
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
Generic Aurora engines (debug) console.
StackException Exception
Definition: error.h:59
bool _newCampaignStandalone
Is the campaign to change to a stand-alone module?
Definition: campaign.h:137
static UString getDirectory(const UString &p)
Return a path&#39;s directory.
Definition: filepath.cpp:107
Aurora::LocString _description
The description of the currently loaded campaign.
Definition: campaign.h:121
void unload(bool completeUnload=true)
Unload the whole shebang.
Definition: campaign.cpp:89
std::vector< const GFF3Struct * > GFF3List
Definition: types.h:449
#define EventMan
Shortcut for accessing the events manager.
Definition: events.h:210
Implementing the stream reading interfaces for files.
static Common::UString getDirectory(const Common::UString &campaign)
Return the actual real directory for this campaign.
Definition: campaign.cpp:152
const GFF3List & getList(const Common::UString &field) const
Definition: gff3file.cpp:741
void replaceCampaign()
Actually replace the currently running campaign.
Definition: campaign.cpp:308
Campaign(::Engines::Console &console)
Definition: campaign.cpp:50
static UString relativize(const UString &basePath, const UString &path)
Return the path relative to the base path.
Definition: filepath.cpp:142
A list of files.
Definition: filelist.h:35
void usePC(const Common::UString &utc)
Use this character as the player character.
Definition: campaign.cpp:218
The context needed to run a The Witcher module.
bool _hasCampaign
Do we have a campaign?
Definition: campaign.h:114
bool processEvent(const Events::Event &event)
Definition: console.cpp:817
#define CameraMan
Shortcut for accessing the camera manager.
Definition: camera.h:83
Common::UString getString(const Common::UString &field, const Common::UString &def="") const
Definition: gff3file.cpp:527
A list of files.
Common::UString _newCampaign
The campaign we should change to.
Definition: campaign.h:135
std::list< Common::UString > _modules
All modules used by the current campaign.
Definition: campaign.h:124
bool isRunning() const
Is a campaign currently running?
Definition: campaign.cpp:85
void leave()
Leave the running campaign, quitting it.
Definition: campaign.cpp:250
Engine utility class for free-roam camera handling.
void clear()
Clear the string&#39;s contents.
Definition: ustring.cpp:236
static UString getFile(const UString &p)
Return a file name without its path.
Definition: filepath.cpp:81
Interface for a seekable & readable data stream.
Definition: readstream.h:265
static Common::UString findModule(const Common::UString &module, bool relative)
Definition: module.cpp:551
The global resource manager for Aurora resources.
Utility class for manipulating file paths.
void loadModule(const Common::UString &module)
Load a stand-alone module as a campaign.
Definition: campaign.cpp:127