xoreos  0.0.5
area.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/strutil.h"
27 #include "src/common/error.h"
28 
29 #include "src/aurora/resman.h"
30 #include "src/aurora/rimfile.h"
31 #include "src/aurora/gff3file.h"
32 #include "src/aurora/gff4file.h"
33 
34 #include "src/graphics/graphics.h"
36 
38 
39 #include "src/events/events.h"
40 
48 
49 namespace Engines {
50 
51 namespace DragonAge {
52 
53 static const uint32 kARLID = MKTAG('A', 'R', 'L', ' ');
54 static const uint32 kAREID = MKTAG('A', 'R', 'E', ' ');
55 static const uint32 kVersion40 = MKTAG('V', '4', '.', '0');
56 
57 static const uint32 kROOMID = MKTAG('R', 'O', 'O', 'M');
58 
59 using ::Aurora::GFF3File;
60 using ::Aurora::GFF3Struct;
62 
63 using ::Aurora::GFF4File;
64 using ::Aurora::GFF4Struct;
66 
67 using namespace ::Aurora::GFF4FieldNamesEnum;
68 
69 Area::Area(Campaign &campaign, const Common::UString &resRef,
70  const Common::UString &env, const Common::UString &rim) :
71  Object(kObjectTypeArea), _campaign(&campaign), _resRef(resRef), _environmentID(0xFFFFFFFF), _activeObject(0), _highlightAll(0) {
72 
73  try {
74 
75  load(resRef, env, rim);
76 
77  } catch (Common::Exception &e) {
78  clean();
79 
80  e.add("Failed loading area \"%s\"", resRef.c_str());
81  throw e;
82  }
83 }
84 
86  hide();
87  clean();
88 }
89 
91  return _resRef;
92 }
93 
95  return _name;
96 }
97 
98 void Area::clean() {
99  try {
100  for (Objects::iterator o = _objects.begin(); o != _objects.end(); ++o)
101  _campaign->removeObject(**o);
102 
104  } catch (...) {
105  }
106 }
107 
108 void Area::load(const Common::UString &resRef, const Common::UString &env, const Common::UString &rim) {
109  indexOptionalArchive(rim + ".rim", 11000, _resources);
110 
111  loadEnvironment(env);
112  loadARE(resRef);
113 }
114 
116  GFF4File arl(resRef, Aurora::kFileTypeARL, kARLID);
117  if (arl.getTypeVersion() != kVersion40)
118  throw Common::Exception("Unsupported ARL version %s", Common::debugTag(arl.getTypeVersion()).c_str());
119 
120  const GFF4Struct &arlTop = arl.getTopLevel();
121 
122  _environmentID = (uint32) ((int32) arlTop.getSint(kGFF4EnvAreaID, -1));
123 
124  _environmentName = arlTop.getString(kGFF4EnvAreaName);
125  _skyDome = arlTop.getString(kGFF4EnvAreaSkydomeModel);
126 
127  _startPoint = arlTop.getString(kGFF4EnvAreaStartPointName);
128 
129  const Common::UString layout = arlTop.getString(kGFF4EnvAreaLayoutName);
130  if (!layout.empty()) {
131  indexOptionalArchive(layout + ".rim" , 11001, _resources);
132  indexOptionalArchive(layout + ".gpu.rim", 11002, _resources);
133  }
134 
135  const GFF4List &rooms = arlTop.getList(kGFF4EnvAreaRoomList);
136  _rooms.reserve(rooms.size());
137 
138  for (GFF4List::const_iterator r = rooms.begin(); r != rooms.end(); ++r) {
139  if (EventMan.quitRequested())
140  break;
141 
142  if (!*r || ((*r)->getLabel() != kROOMID))
143  continue;
144 
145  _rooms.push_back(new Room(**r));
146  }
147 }
148 
149 void Area::loadARE(const Common::UString &resRef) {
150  GFF3File are(resRef, Aurora::kFileTypeARE, kAREID);
151 
152  const GFF3Struct &areTop = are.getTopLevel();
153 
154  _tag = areTop.getString("Tag");
155 
156  areTop.getLocString("Name", _name);
157 
158  readVarTable(areTop);
159  readScript(areTop);
160  enableEvents(true);
161 
162  if (areTop.hasField("WaypointList"))
163  loadWaypoints (areTop.getList("WaypointList"));
164  if (areTop.hasField("PlaceableList"))
165  loadPlaceables(areTop.getList("PlaceableList"));
166  if (areTop.hasField("CreatureList"))
167  loadCreatures (areTop.getList("CreatureList"));
168 }
169 
171  _objects.push_back(&object);
172 
173  _campaign->addObject(object);
174 
175  if (!object.isStatic()) {
176  const std::list<uint32> &ids = object.getIDs();
177 
178  for (std::list<uint32>::const_iterator id = ids.begin(); id != ids.end(); ++id)
179  _objectMap.insert(std::make_pair(*id, &object));
180  }
181 }
182 
184  for (Aurora::GFF3List::const_iterator w = list.begin(); w != list.end(); ++w) {
185  Waypoint *waypoint = new Waypoint(**w);
186 
187  loadObject(*waypoint);
188  }
189 }
190 
192  for (Aurora::GFF3List::const_iterator p = list.begin(); p != list.end(); ++p) {
193  Placeable *placeable = new Placeable(**p);
194 
195  loadObject(*placeable);
196  }
197 }
198 
200  for (Aurora::GFF3List::const_iterator c = list.begin(); c != list.end(); ++c) {
201  Creature *creature = new Creature(**c);
202 
203  loadObject(*creature);
204  }
205 }
206 
207 void Area::show() {
208  _eventQueue.clear();
209 
210  GfxMan.lockFrame();
211 
212  for (Rooms::iterator r = _rooms.begin(); r != _rooms.end(); ++r)
213  (*r)->show();
214  for (Objects::iterator o = _objects.begin(); o != _objects.end(); ++o)
215  (*o)->show();
216 
217  GfxMan.unlockFrame();
218 }
219 
220 void Area::hide() {
221  GfxMan.lockFrame();
222 
223  removeFocus();
224 
225  for (Objects::iterator o = _objects.begin(); o != _objects.end(); ++o)
226  (*o)->hide();
227  for (Rooms::iterator r = _rooms.begin(); r != _rooms.end(); ++r)
228  (*r)->hide();
229 
230  GfxMan.unlockFrame();
231 }
232 
234  if (!rimFile.empty()) {
235 
236  try {
237  Common::SeekableReadStream *rimStream = ResMan.getResource(rimFile, Aurora::kFileTypeRIM);
238  if (!rimStream)
239  throw 0;
240 
241  const Aurora::RIMFile rim(rimStream);
242  const uint32 areIndex = rim.findResource(resRef, Aurora::kFileTypeARE);
243 
244  const GFF3File are(rim.getResource(areIndex), kAREID);
245 
246  return are.getTopLevel().getString("Name");
247  } catch (...) {
248  }
249 
250  }
251 
252  try {
253  const GFF3File are(resRef, Aurora::kFileTypeARE, kAREID);
254 
255  return are.getTopLevel().getString("Name");
256  } catch (...) {
257  }
258 
259  return "";
260 }
261 
262 void Area::getEntryLocation(float &posX, float &posY, float &posZ,
263  float &orientX, float &orientY, float &orientZ, float &orientAngle) const {
264 
265  DragonAge::Object *object = 0;
266 
268  if (!object)
270  if (!object)
272 
273  if (object) {
274  object->getPosition(posX, posY, posZ);
275  object->getOrientation(orientX, orientY, orientZ, orientAngle);
276  return;
277  }
278 
279  posX = 0.0f;
280  posY = 0.0f;
281  posZ = 0.0f;
282 
283  orientX = 0.0f;
284  orientY = 0.0f;
285  orientZ = 0.0f;
286 
287  orientAngle = 0.0f;
288 }
289 
290 void Area::addEvent(const Events::Event &event) {
291  _eventQueue.push_back(event);
292 }
293 
295  bool hasMove = false;
296  for (std::list<Events::Event>::const_iterator e = _eventQueue.begin();
297  e != _eventQueue.end(); ++e) {
298 
299  if (e->type == Events::kEventMouseMove) { // Moving the mouse
300  hasMove = true;
301  } else if (e->type == Events::kEventMouseDown) { // Clicking
302  if (e->button.button == SDL_BUTTON_LMASK) {
303  checkActive(e->button.x, e->button.y);
304  click(e->button.x, e->button.y);
305  }
306  } else if (e->type == Events::kEventKeyDown) { // Holding down TAB
307  if (e->key.keysym.sym == SDLK_TAB)
308  highlightAll(true);
309  } else if (e->type == Events::kEventKeyUp) { // Releasing TAB
310  if (e->key.keysym.sym == SDLK_TAB)
311  highlightAll(false);
312  }
313  }
314 
315  _eventQueue.clear();
316 
317  if (hasMove)
318  checkActive();
319 }
320 
322  const Graphics::Renderable *obj = GfxMan.getObjectAt(x, y);
323  if (!obj)
324  return 0;
325 
326  ObjectMap::iterator o = _objectMap.find(obj->getID());
327  if (o == _objectMap.end())
328  return 0;
329 
330  return o->second;
331 }
332 
334  if (object == _activeObject)
335  return;
336 
337  if (_activeObject)
338  _activeObject->leave();
339 
340  _activeObject = object;
341 
342  if (_activeObject)
343  _activeObject->enter();
344 }
345 
346 void Area::checkActive(int x, int y) {
347  if (_highlightAll)
348  return;
349 
351 
352  if ((x < 0) || (y < 0))
353  CursorMan.getPosition(x, y);
354 
355  setActive(getObjectAt(x, y));
356 }
357 
358 void Area::click(int x, int y) {
360 
361  DragonAge::Object *o = getObjectAt(x, y);
362  if (!o)
363  return;
364 
365  o->click(_campaign->getPC());
366 }
367 
368 void Area::highlightAll(bool enabled) {
369  if (_highlightAll == enabled)
370  return;
371 
372  _highlightAll = enabled;
373 
374  for (ObjectMap::iterator o = _objectMap.begin(); o != _objectMap.end(); ++o)
375  if (o->second->isClickable())
376  o->second->highlight(enabled);
377 }
378 
380  if (_activeObject)
381  _activeObject->leave();
382 
383  _activeObject = 0;
384 }
385 
387  checkActive();
388 }
389 
390 } // End of namespace DragonAge
391 
392 } // End of namespace Engines
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
A placeable object in a Dragon Age: Origins area.
ObjectMap _objectMap
Map of objects by their model IDs.
Definition: area.h:121
#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
uint32 findResource(uint64 hash) const
Return the index of the resource matching the hash, or 0xFFFFFFFF if not found.
Definition: archive.cpp:48
static const uint32 kROOMID
Definition: area.cpp:57
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
Common::SeekableReadStream * getResource(uint32 index, bool tryNoCopy=false) const
Return a stream of the resource&#39;s contents.
Definition: rimfile.cpp:108
The global graphics manager.
virtual void leave()
The cursor left the object.
Definition: object.cpp:164
::Aurora::NWScript::Object * getFirstObjectByType(ObjectType type) const
Return the first object of this type.
const Aurora::LocString & getName() const
Definition: area.cpp:94
A class holding an UTF-8 string.
Definition: ustring.h:48
DragonAge::Object * getObjectAt(int x, int y)
Definition: area.cpp:321
void loadObject(DragonAge::Object &object)
Definition: area.cpp:170
A localized string.
Definition: locstring.h:43
The context holding a Dragon Age: Origins campaign.
Handling BioWare&#39;s RIMs (resource archives).
void hide()
Hide the object&#39;s model(s).
Definition: area.cpp:220
bool indexOptionalArchive(const Common::UString &file, uint32 priority, const std::vector< byte > &password, Common::ChangeID *changeID)
Definition: resources.cpp:69
virtual void enter()
The cursor entered the object.
Definition: object.cpp:161
A creature in a Dragon Age: Origins area.
static const uint32 kARLID
Definition: area.cpp:53
void loadPlaceables(const Aurora::GFF3List &list)
Definition: area.cpp:191
Common::UString _environmentName
Definition: area.h:107
A waypoint in a Dragon Age: Origins area.
Module resources, RIM.
Definition: types.h:178
Common::UString _startPoint
Definition: area.h:110
A room in a Dragon Age: Origins area.
void loadEnvironment(const Common::UString &resRef)
Definition: area.cpp:115
ChangeList _resources
Definition: area.h:117
void click(int x, int y)
Definition: area.cpp:358
Object * getFirstObject() const
Return the first object.
Utility templates and functions for working with strings and streams.
void addEvent(const Events::Event &event)
Add a single event for consideration into the area event queue.
Definition: area.cpp:290
Mouse was moved.
Definition: types.h:48
Exception that provides a stack of explanations.
Definition: error.h:36
SDL_Event Event
Definition: types.h:42
void show()
Show the object&#39;s model(s).
Definition: area.cpp:207
Objects _objects
List of all objects in the area.
Definition: area.h:120
void deindexResources(Common::ChangeID &changeID)
Remove previously added resources from the ResourceManager.
Definition: resources.cpp:164
Mouse button was pressed.
Definition: types.h:49
Keyboard key was pressed.
Definition: types.h:46
The context holding a Dragon Age: Origins area.
std::vector< const GFF4Struct * > GFF4List
Definition: types.h:453
Area layout.
Definition: types.h:308
Handling version V4.0/V4.1 of BioWare&#39;s GFFs (generic file format).
Common::Mutex _mutex
Definition: area.h:128
Basic exceptions to throw.
void setActive(DragonAge::Object *object)
Definition: area.cpp:333
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
DragonAge::Object * _activeObject
The currently active (highlighted) object.
Definition: area.h:124
Utility templates and functions.
void processEventQueue()
Process the current event queue.
Definition: area.cpp:294
Creature * getPC() const
Return the currently playing PC.
Definition: campaign.cpp:295
The global events manager.
void checkActive(int x=-1, int y=-1)
Definition: area.cpp:346
static const uint32 kVersion40
Definition: area.cpp:55
void removeFocus()
Forcibly remove the focus from the currently highlighted object.
Definition: area.cpp:379
static const uint32 kAREID
Definition: area.cpp:54
Common::UString _resRef
Definition: area.h:104
static DragonAge::Object * toObject(::Aurora::NWScript::Object *object)
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
void loadWaypoints(const Aurora::GFF3List &list)
Definition: area.cpp:183
void addObject(DragonAge::Object &object)
Add an object to this container.
virtual bool click(Object *triggerer=0)
The object was clicked.
Definition: object.cpp:170
#define CursorMan
Shortcut for accessing the cursor manager.
Definition: cursorman.h:129
void getEntryLocation(float &posX, float &posY, float &posZ, float &orientX, float &orientY, float &orientZ, float &orientAngle) const
Return the position and orientation the PC should enter this area.
Definition: area.cpp:262
std::vector< const GFF3Struct * > GFF3List
Definition: types.h:449
Convenience class that locks a mutex on creation and unlocks it on destruction.
Definition: mutex.h:71
#define EventMan
Shortcut for accessing the events manager.
Definition: events.h:210
The Aurora cursor manager.
void loadARE(const Common::UString &resRef)
Definition: area.cpp:149
void readVarTable(const Aurora::GFF3List &varTable)
An object that can be displayed by the graphics manager.
Definition: renderable.h:42
An object in a Dragon Age: Origins area.
uint32 getID() const
Get the object&#39;s unique ID.
Definition: renderable.cpp:86
std::list< Events::Event > _eventQueue
Definition: area.h:118
Aurora::LocString _name
Definition: area.h:113
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
void loadCreatures(const Aurora::GFF3List &list)
Definition: area.cpp:199
Common::UString _tag
Definition: object.h:56
Static area data, GFF.
Definition: types.h:81
bool isStatic() const
Is the object static (not manipulable at all)?
Definition: object.cpp:108
Common::UString _skyDome
Definition: area.h:108
void readScript(const Aurora::GFF3Struct &gff)
Definition: container.cpp:90
Class to hold resource data of a RIM archive file.
Definition: rimfile.h:61
void load(const Common::UString &resRef, const Common::UString &env, const Common::UString &rim)
Definition: area.cpp:108
bool _highlightAll
Are we currently highlighting all objects?
Definition: area.h:126
void highlightAll(bool enabled)
Definition: area.cpp:368
Campaign * _campaign
Definition: area.h:102
Keyboard key was released.
Definition: types.h:47
Area(Campaign &campaign, const Common::UString &resRef, const Common::UString &env, const Common::UString &rim)
Definition: area.cpp:69
virtual void getPosition(float &x, float &y, float &z) const
Return the object&#39;s position within its area.
Definition: object.cpp:120
An object that can be displayed by the graphics manager.
Object * getFirstObjectByTag(const Common::UString &tag) const
Return the first object with this tag.
Interface for a seekable & readable data stream.
Definition: readstream.h:265
void enableEvents(bool enabled)
Enable/Disable the handling of all events.
Definition: container.cpp:76
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
The global resource manager for Aurora resources.
int32_t int32
Definition: types.h:203
const Common::UString & getResRef() const
Definition: area.cpp:90
void removeObject(DragonAge::Object &object)
Remove an object from this container.