xoreos  0.0.5
creature.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/maths.h"
27 #include "src/common/error.h"
28 #include "src/common/ustring.h"
29 #include "src/common/strutil.h"
30 
31 #include "src/aurora/2dafile.h"
32 #include "src/aurora/2dareg.h"
33 #include "src/aurora/gff3file.h"
34 
38 
41 
44 
45 namespace Engines {
46 
47 namespace KotOR2 {
48 
50  init();
51  load(creature);
52 }
53 
55  init();
56 }
57 
59 }
60 
62  _isPC = false;
63 
65 }
66 
68  if (_model)
69  _model->show();
70 }
71 
73  if (_model)
74  _model->hide();
75 }
76 
77 bool Creature::isVisible() const {
78  return _model && _model->isVisible();
79 }
80 
81 bool Creature::isPC() const {
82  return _isPC;
83 }
84 
86  return _isPC;
87 }
88 
89 void Creature::setPosition(float x, float y, float z) {
90  Object::setPosition(x, y, z);
91  Object::getPosition(x, y, z);
92 
93  if (_model)
94  _model->setPosition(x, y, z);
95 }
96 
97 void Creature::setOrientation(float x, float y, float z, float angle) {
98  Object::setOrientation(x, y, z, angle);
99  Object::getOrientation(x, y, z, angle);
100 
101  if (_model)
102  _model->setOrientation(x, y, z, angle);
103 }
104 
105 void Creature::load(const Aurora::GFF3Struct &creature) {
106  Common::UString temp = creature.getString("TemplateResRef");
107 
109  if (!temp.empty())
110  utc.reset(loadOptionalGFF3(temp, Aurora::kFileTypeUTC, MKTAG('U', 'T', 'C', ' ')));
111 
112  load(creature, utc ? &utc->getTopLevel() : 0);
113 
114  if (!utc)
115  warning("Creature \"%s\" has no blueprint", _tag.c_str());
116 }
117 
118 void Creature::load(const Aurora::GFF3Struct &instance, const Aurora::GFF3Struct *blueprint) {
119  // General properties
120 
121  if (blueprint)
122  loadProperties(*blueprint); // Blueprint
123  loadProperties(instance); // Instance
124 
125 
126  // Appearance
127 
129  throw Common::Exception("Creature without an appearance");
130 
131  loadAppearance();
132 
133  // Position
134 
135  setPosition(instance.getDouble("XPosition"),
136  instance.getDouble("YPosition"),
137  instance.getDouble("ZPosition"));
138 
139  // Orientation
140 
141  float bearingX = instance.getDouble("XOrientation");
142  float bearingY = instance.getDouble("YOrientation");
143 
144  setOrientation(0.0f, 0.0f, 1.0f, -Common::rad2deg(atan2(bearingX, bearingY)));
145 }
146 
148  // Tag
149  _tag = gff.getString("Tag", _tag);
150 
151  // Name
152  _name = gff.getString("Name", _name);
153 
154  // Description
155  _description = gff.getString("Description", _description);
156 
157  // Portrait
158  loadPortrait(gff);
159 
160  // Appearance
161  _appearance = gff.getUint("Appearance_Type", _appearance);
162 
163  // Static
164  _static = gff.getBool("Static", _static);
165 
166  // Usable
167  _usable = gff.getBool("Useable", _usable);
168 
169  // PC
170  _isPC = gff.getBool("IsPC", _isPC);
171 
172  // Scripts
173  readScripts(gff);
174 
175  _conversation = gff.getString("Conversation", _conversation);
176 }
177 
179  uint32 portraitID = gff.getUint("PortraitId");
180  if (portraitID != 0) {
181  const Aurora::TwoDAFile &twoda = TwoDAReg.get2DA("portraits");
182 
183  Common::UString portrait = twoda.getRow(portraitID).getString("BaseResRef");
184  if (!portrait.empty())
185  _portrait = "po_" + portrait;
186  }
187 
188  _portrait = gff.getString("Portrait", _portrait);
189 }
190 
192  PartModels parts;
193 
194  getPartModels(parts);
195 
196  if ((_modelType == "P") || parts.body.empty()) {
197  warning("TODO: Model \"%s\": ModelType \"%s\" (\"%s\")",
198  _tag.c_str(), _modelType.c_str(), parts.body.c_str());
199  return;
200  }
201 
202  loadBody(parts);
203  loadHead(parts);
204 
206 }
207 
209  const Aurora::TwoDARow &appearance = TwoDAReg.get2DA("appearance").getRow(_appearance);
210 
211  _modelType = appearance.getString("modeltype");
212 
213  // TODO: load state based on character equipment
214  if (appearance.getString("label").beginsWith("Party_"))
215  state = 'b';
216 
217  if (_modelType == "B") {
218  parts.body = appearance.getString(Common::UString("model") + state);
219  parts.bodyTexture = appearance.getString(Common::UString("tex") + state) + "01";
220  } else {
221  parts.body = appearance.getString("race");
222  parts.bodyTexture = appearance.getString("racetex");
223  }
224 
225  if ((_modelType == "B") || (_modelType == "P")) {
226  const int headNormalID = appearance.getInt("normalhead");
227  const int headBackupID = appearance.getInt("backuphead");
228 
229  const Aurora::TwoDAFile &heads = TwoDAReg.get2DA("heads");
230 
231  if (headNormalID >= 0)
232  parts.head = heads.getRow(headNormalID).getString("head");
233  else if (headBackupID >= 0)
234  parts.head = heads.getRow(headBackupID).getString("head");
235  }
236 }
237 
240  if (!_model)
241  return;
242 
243  _ids.push_back(_model->getID());
244 
245  _model->setTag(_tag);
246  _model->setClickable(isClickable());
247 
248  if (_modelType != "B" && _modelType != "P")
249  _model->addAnimationChannel(Graphics::Aurora::kAnimationChannelHead);
250 }
251 
253  if (!_model || parts.head.empty())
254  return;
255 
256  Graphics::Aurora::Model *headModel = loadModelObject(parts.head);
257  if (!headModel)
258  return;
259 
260  _model->attachModel("headhook", headModel);
261 }
262 
264  _name = "Fakoo McFakeston";
265  _tag = Common::UString::format("[PC: %s]", _name.c_str());
266 
267  _isPC = true;
268 }
269 
271  _name = info.getName();
272  _isPC = true;
273 
274  PartModels parts;
275 
276  parts.body = info.getBodyId();
277  parts.bodyTexture = info.getBodyTextureId();
278  parts.head = info.getHeadId();
279 
280  loadBody(parts);
281  loadHead(parts);
282 
284 }
285 
287  highlight(true);
288 }
289 
291  highlight(false);
292 }
293 
294 void Creature::highlight(bool enabled) {
295  _model->drawBound(enabled);
296 }
297 
298 bool Creature::click(Object *triggerer) {
299  // Try the onDialog script first
301  return runScript(kScriptDialogue, this, triggerer);
302 
303  // Next, look we have a generic onClick script
304  if (hasScript(kScriptClick))
305  return runScript(kScriptClick, this, triggerer);
306 
307  return false;
308 }
309 
311  return _conversation;
312 }
313 
315  float height = 1.8f;
316  if (_model) {
317  Graphics::Aurora::ModelNode *node = _model->getNode("camerahook");
318  if (node) {
319  float x, y, z;
320  node->getPosition(x, y, z);
321  height = z;
322  }
323  }
324  return height;
325 }
326 
328  if (_model)
329  _model->playDefaultAnimation();
330 }
331 
333  if (!_model)
334  return;
335 
336  Graphics::Aurora::AnimationChannel *headChannel = 0;
337 
338  if (_modelType == "B" || _modelType == "P") {
339  Graphics::Aurora::Model *head = _model->getAttachedModel("headhook");
340  if (head)
342  } else
343  headChannel = _model->getAnimationChannel(Graphics::Aurora::kAnimationChannelHead);
344 
345  if (headChannel)
346  headChannel->playDefaultAnimation();
347 }
348 
349 void Creature::playAnimation(const Common::UString &anim, bool restart, float length, float speed) {
350  if (_model)
351  _model->playAnimation(anim, restart, length, speed);
352 }
353 
354 void Creature::playHeadAnimation(const Common::UString &anim, bool restart, float length, float speed) {
355  if (!_model)
356  return;
357 
358  Graphics::Aurora::AnimationChannel *headChannel = 0;
359 
360  if (_modelType == "B" || _modelType == "P") {
361  Graphics::Aurora::Model *head = _model->getAttachedModel("headhook");
362  if (head)
364  } else
365  headChannel = _model->getAnimationChannel(Graphics::Aurora::kAnimationChannelHead);
366 
367  if (headChannel)
368  headChannel->playAnimation(anim, restart, length, speed);
369 }
370 
372  if (!_model)
373  return;
374 
375  if (_modelType == "S" || _modelType == "L")
376  _model->addDefaultAnimation("cpause1", 100);
377  else
378  _model->addDefaultAnimation("pause1", 100);
379 }
380 
381 } // End of namespace KotOR2
382 
383 } // End of namespace Engines
Common::UString _conversation
Definition: creature.h:121
Class to hold the two-dimensional array of a 2DA file.
Definition: 2dafile.h:124
Handling version V3.2/V3.3 of BioWare&#39;s GFFs (generic file format).
#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 setPosition(float x, float y, float z)
Set the creature&#39;s position.
Definition: creature.cpp:89
void playAnimation(const Common::UString &anim, bool restart=true, float length=0.0f, float speed=1.0f)
Play a named animation.
A creature in a Star Wars: Knights of the Old Republic II - The Sith Lords area.
void highlight(bool enabled)
(Un)Highlight the creature.
Definition: creature.cpp:294
bool isPartyMember() const
Definition: creature.cpp:85
virtual void getPosition(float &x, float &y, float &z) const
Return the object&#39;s position within its area.
Definition: object.cpp:107
const Common::UString & getString(size_t column) const
Return the contents of a cell as a string.
Definition: 2dafile.cpp:59
bool getBool(const Common::UString &field, bool def=false) const
Definition: gff3file.cpp:510
A class holding an UTF-8 string.
Definition: ustring.h:48
bool isVisible() const
Is the creature&#39;s model visible?
Definition: creature.cpp:77
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
bool beginsWith(const UString &with) const
Definition: ustring.cpp:295
void loadBody(PartModels &parts)
Definition: creature.cpp:238
Mathematical helpers.
The KotOR 2 character generation info.
virtual void setPosition(float x, float y, float z)
Set the object&#39;s position within its area.
Definition: object.cpp:121
void loadHead(PartModels &parts)
Definition: creature.cpp:252
uint64 getUint(const Common::UString &field, uint64 def=0) const
Definition: gff3file.cpp:436
bool _usable
Is the object usable?
Definition: object.h:135
void createPC(const CharacterGenerationInfo &info)
Create a player character creature.
Definition: creature.cpp:270
void playAnimation(const Common::UString &anim, bool restart=true, float length=0.0f, float speed=1.0f)
Definition: creature.cpp:349
void getPosition(float &x, float &y, float &z) const
Get the position of the node.
Definition: modelnode.cpp:181
Aurora::GFF3File * loadOptionalGFF3(const Common::UString &gff3, Aurora::FileType type, uint32 id, bool repairNWNPremium)
Load a GFF3, but return 0 instead of throwing on error.
Definition: util.cpp:150
virtual void getOrientation(float &x, float &y, float &z, float &angle) const
Return the object&#39;s orientation.
Definition: object.cpp:113
Utility templates and functions for working with strings and streams.
void load(const Aurora::GFF3Struct &creature)
Definition: creature.cpp:105
void loadProperties(const Aurora::GFF3Struct &gff)
Definition: creature.cpp:147
void enter()
The cursor entered the creature.
Definition: creature.cpp:286
Basic exceptions to throw.
bool isClickable() const
Can the player click the object?
Definition: object.cpp:99
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
void leave()
The cursor left the creature.
Definition: creature.cpp:290
void playHeadAnimation(const Common::UString &anim, bool restart=true, float length=0.0f, float speed=1.0f)
Definition: creature.cpp:354
static UString format(const char *s,...) GCC_PRINTF(1
Print formatted data into an UString object, similar to sprintf().
Definition: ustring.cpp:718
std::list< uint32 > _ids
The object&#39;s model IDs.
Definition: object.h:137
Common::UString _name
The object&#39;s display name.
Definition: object.h:129
Utility templates and functions.
double getDouble(const Common::UString &field, double def=0.0) const
Definition: gff3file.cpp:514
Common::UString _portrait
The object&#39;s portrait.
Definition: object.h:132
Handling BioWare&#39;s 2DAs (two-dimensional array).
bool _isPC
Is the creature a PC?
Definition: creature.h:116
void info(const char *s,...)
Definition: util.cpp:69
bool runScript(Script script, const Aurora::NWScript::ObjectReference owner=Aurora::NWScript::ObjectReference(), const Aurora::NWScript::ObjectReference triggerer=Aurora::NWScript::ObjectReference())
Definition: container.cpp:150
A node within a 3D model.
void getPartModels(PartModels &parts, uint32 state='a')
Definition: creature.cpp:208
A 3D model of an object.
float getCameraHeight() const
Definition: creature.cpp:314
Parts of a creature&#39;s body.
Definition: creature.h:107
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
#define TwoDAReg
Shortcut for accessing the 2da registry.
Definition: 2dareg.h:101
StackException Exception
Definition: error.h:59
Common::UString _modelType
Definition: creature.h:122
The global 2DA registry.
const Common::UString & getConversation() const
Definition: creature.cpp:310
void warning(const char *s,...)
Definition: util.cpp:33
int32 getInt(size_t column) const
Return the contents of a cell as an int.
Definition: 2dafile.cpp:75
AnimationChannel * getAnimationChannel(AnimationChannelName name)
Definition: model.cpp:537
Unicode string handling.
const TwoDARow & getRow(size_t row) const
Get a row.
Definition: 2dafile.cpp:421
uint32 _appearance
The creature&#39;s general appearance.
Definition: creature.h:118
bool isPC() const
Is the creature a player character?
Definition: creature.cpp:81
A struct within a GFF3.
Definition: gff3file.h:164
uint32_t uint32
Definition: types.h:204
Common::UString _tag
Definition: object.h:56
static const uint32 kFieldIDInvalid
Definition: types.h:443
virtual void setOrientation(float x, float y, float z, float angle)
Set the object&#39;s orientation.
Definition: object.cpp:127
bool _static
Is the object static?
Definition: object.h:134
void hide()
Hide the creature&#39;s model.
Definition: creature.cpp:72
Common::UString getString(const Common::UString &field, const Common::UString &def="") const
Definition: gff3file.cpp:527
static float rad2deg(float rad)
Definition: maths.h:93
Common::ScopedPtr< Graphics::Aurora::Model > _model
The creature&#39;s model.
Definition: creature.h:120
Generic Aurora engines utility functions.
void readScripts(const Aurora::GFF3Struct &gff)
Definition: container.cpp:134
void setOrientation(float x, float y, float z, float angle)
Set the creature&#39;s orientation.
Definition: creature.cpp:97
void createFakePC()
Create a fake player character creature for testing purposes.
Definition: creature.cpp:263
Animation channel.
Creature()
Create a dummy creature instance.
Definition: creature.cpp:54
bool hasScript(Script script) const
Definition: container.cpp:125
Graphics::Aurora::Model * loadModelObject(const Common::UString &resref, const Common::UString &texture)
Definition: model.cpp:47
A row within a 2DA file.
Definition: 2dafile.h:61
void show()
Show the creature&#39;s model.
Definition: creature.cpp:67
Creature template (user), GFF.
Definition: types.h:93
bool click(Object *triggerer=0)
The creature was clicked.
Definition: creature.cpp:298
Common::UString _description
The object&#39;s description.
Definition: object.h:130
void loadPortrait(const Aurora::GFF3Struct &gff)
Definition: creature.cpp:178
Generic Aurora engines model functions.