ScummVM API documentation
actor.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 // Actor management module header file
23 
24 #ifndef SAGA_ACTOR_H
25 #define SAGA_ACTOR_H
26 
27 #include "common/savefile.h"
28 
29 #include "saga/sprite.h"
30 #include "saga/itedata.h"
31 #include "saga/saga.h"
32 #include "saga/font.h"
33 
34 namespace Saga {
35 
36 class HitZone;
37 
38 
39 //#define ACTOR_DEBUG 1 //only for actor pathfinding debug!
40 
41 #define ACTOR_BARRIERS_MAX 16
42 
43 #define ACTOR_MAX_STEPS_COUNT 32
44 
45 #define ACTOR_DIALOGUE_HEIGHT 100
46 
47 #define ACTOR_LMULT 4
48 
49 #define ACTOR_SPEED 72
50 
51 #define ACTOR_CLIMB_SPEED 8
52 
53 #define ACTOR_COLLISION_WIDTH 32
54 #define ACTOR_COLLISION_HEIGHT 8
55 
56 #define ACTOR_DIRECTIONS_COUNT 4 // for ActorFrameSequence
57 
58 #define ACTOR_SPEECH_STRING_MAX 16 // speech const
59 #define ACTOR_SPEECH_ACTORS_MAX 8
60 
61 #define ACTOR_DRAGON_TURN_MOVES 4
62 #define ACTOR_DRAGON_INDEX 133
63 
64 #define ACTOR_NO_ENTRANCE -1
65 
66 #define ACTOR_EXP_KNOCK_RIF 24
67 
68 #define PATH_NODE_EMPTY -1
69 
70 #define ACTOR_INHM_SIZE 228
71 
72 enum ActorDirections {
73  kDirectionRight = 0,
74  kDirectionLeft = 1,
75  kDirectionUp = 2,
76  kDirectionDown = 3
77 };
78 
79 enum ActorActions {
80  kActionWait = 0,
81  kActionWalkToPoint = 1,
82  kActionWalkToLink = 2,
83  kActionWalkDir = 3,
84  kActionSpeak = 4,
85  kActionAccept = 5,
86  kActionStoop = 6,
87  kActionLook = 7,
88  kActionCycleFrames = 8,
89  kActionPongFrames = 9,
90  kActionFreeze = 10,
91  kActionFall = 11,
92  kActionClimb = 12
93 };
94 
95 enum ActorFrameIds {
96 //ITE
97  kFrameITEStand = 0,
98  kFrameITEWalk = 1,
99  kFrameITESpeak = 2,
100  kFrameITEGive = 3,
101  kFrameITEGesture = 4,
102  kFrameITEWait = 5,
103  kFrameITEPickUp = 6,
104  kFrameITELook = 7,
105 //IHNM
106  kFrameIHNMStand = 0,
107  kFrameIHNMSpeak = 1,
108  kFrameIHNMWait = 2,
109  kFrameIHNMGesture = 3,
110  kFrameIHNMWalk = 4
111 };
112 
113 enum SpeechFlags {
114  kSpeakNoAnimate = 1,
115  kSpeakAsync = 2,
116  kSpeakSlow = 4,
117  kSpeakForceText = 8
118 };
119 
120 enum ActorFrameTypes {
121  kFrameStand,
122  kFrameWalk,
123  kFrameSpeak,
124  kFrameGive,
125  kFrameGesture,
126  kFrameWait,
127  kFramePickUp,
128  kFrameLook
129 };
130 
131 // Lookup table to convert 8 cardinal directions to 4
132 static const int actorDirectionsLUT[8] = {
133  kDirectionUp, // kDirUp
134  kDirectionRight, // kDirUpRight
135  kDirectionRight, // kDirRight
136  kDirectionRight, // kDirDownRight
137  kDirectionDown, // kDirDown
138  kDirectionLeft, // kDirDownLeft
139  kDirectionLeft, // kDirLeft
140  kDirectionLeft // kDirUpLeft
141 };
142 
143 enum ActorFlagsEx {
144  kActorNoCollide = (1 << 0),
145  kActorNoFollow = (1 << 1),
146  kActorCollided = (1 << 2),
147  kActorBackwards = (1 << 3),
148  kActorContinuous = (1 << 4),
149  kActorFinalFace = (1 << 5),
150  kActorFinishLeft = ((1 << 5) | (kDirLeft << 6)),
151  kActorFinishRight = ((1 << 5) | (kDirRight << 6)),
152  kActorFinishUp = ((1 << 5) | (kDirUp << 6)),
153  kActorFinishDown = ((1 << 5) | (kDirDown << 6)),
154  kActorFacingMask = (0xf << 5),
155  kActorRandom = (1 << 10)
156 };
157 
158 enum PathCellType {
159  kPathCellEmpty = -1,
160  //kDirUp = 0 .... kDirUpLeft = 7
161  kPathCellBarrier = 0x57
162 };
163 
164 enum DragonMoveTypes {
165  kDragonMoveUpLeft = 0,
166  kDragonMoveUpRight = 1,
167  kDragonMoveDownLeft = 2,
168  kDragonMoveDownRight = 3,
169  kDragonMoveUpLeft_Left = 4,
170  kDragonMoveUpLeft_Right = 5,
171  kDragonMoveUpRight_Left = 6,
172  kDragonMoveUpRight_Right = 7,
173  kDragonMoveDownLeft_Left = 8,
174  kDragonMoveDownLeft_Right = 9,
175  kDragonMoveDownRight_Left = 10,
176  kDragonMoveDownRight_Right = 11,
177  kDragonMoveInvalid = 12
178 };
179 
181  int8 direction;
182  int32 x;
183  int32 y;
184 };
185 
187  int frameIndex;
188  int frameCount;
189 };
190 
192  ActorFrameRange directions[ACTOR_DIRECTIONS_COUNT];
193 };
194 
196 
197 uint pathLine(PointList &pointList, uint idx, const Point &point1, const Point &point2);
198 
199 struct Location {
200  int32 x; // logical coordinates
201  int32 y; //
202  int32 z; //
203  Location() {
204  x = y = z = 0;
205  }
206  void saveState(Common::OutSaveFile *out) {
207  out->writeSint32LE(x);
208  out->writeSint32LE(y);
209  out->writeSint32LE(z);
210  }
211  void loadState(Common::InSaveFile *in) {
212  x = in->readSint32LE();
213  y = in->readSint32LE();
214  z = in->readSint32LE();
215  }
216 
217  int distance(const Location &location) const {
218  return MAX(ABS(x - location.x), ABS(y - location.y));
219  }
220  int32 &u() {
221  return x;
222  }
223  int32 &v() {
224  return y;
225  }
226  int32 u() const {
227  return x;
228  }
229  int32 v() const {
230  return y;
231  }
232  int32 uv() const {
233  return u() + v();
234  }
235  void delta(const Location &location, Location &result) const {
236  result.x = x - location.x;
237  result.y = y - location.y;
238  result.z = z - location.z;
239  }
240  void addXY(const Location &location) {
241  x += location.x;
242  y += location.y;
243  }
244  void add(const Location &location) {
245  x += location.x;
246  y += location.y;
247  z += location.z;
248  }
249  void fromScreenPoint(const Point &screenPoint) {
250  x = (screenPoint.x * ACTOR_LMULT);
251  y = (screenPoint.y * ACTOR_LMULT);
252  z = 0;
253  }
254  void toScreenPointXY(Point &screenPoint) const {
255  screenPoint.x = x / ACTOR_LMULT;
256  screenPoint.y = y / ACTOR_LMULT;
257  }
258  void toScreenPointUV(Point &screenPoint) const {
259  screenPoint.x = u();
260  screenPoint.y = v();
261  }
262  void toScreenPointXYZ(Point &screenPoint) const {
263  screenPoint.x = x / ACTOR_LMULT;
264  screenPoint.y = y / ACTOR_LMULT - z;
265  }
266  void fromStream(Common::ReadStream &stream) {
267  x = stream.readUint16LE();
268  y = stream.readUint16LE();
269  z = stream.readUint16LE();
270  }
271 };
272 
274 public:
275 //constant
276  int32 _index; // index in local array
277  uint16 _id; // object id
278  int32 _scriptEntrypointNumber; // script entrypoint number
279 
280 //variables
281  uint16 _flags; // initial flags
282  int32 _nameIndex; // index in name string list
283  int32 _sceneNumber; // scene
284  int32 _spriteListResourceId; // sprite list resource id
285 
286  Location _location; // logical coordinates
287  Point _screenPosition; // screen coordinates
288  int32 _screenDepth; //
289  int32 _screenScale; //
290 
291  void saveState(Common::OutSaveFile *out) {
292  out->writeUint16LE(_flags);
293  out->writeSint32LE(_nameIndex);
294  out->writeSint32LE(_sceneNumber);
295  out->writeSint32LE(_spriteListResourceId);
296  _location.saveState(out);
297  out->writeSint16LE(_screenPosition.x);
298  out->writeSint16LE(_screenPosition.y);
299  out->writeSint32LE(_screenDepth);
300  out->writeSint32LE(_screenScale);
301  }
302  void loadState(Common::InSaveFile *in) {
303  _flags = in->readUint16LE();
304  _nameIndex = in->readSint32LE();
305  _sceneNumber = in->readSint32LE();
306  _spriteListResourceId = in->readSint32LE();
307  _location.loadState(in);
308  _screenPosition.x = in->readSint16LE();
309  _screenPosition.y = in->readSint16LE();
310  _screenDepth = in->readSint32LE();
311  _screenScale = in->readSint32LE();
312  }
313 
314  CommonObjectData() {
315  _index = 0;
316  _id = 0;
317  _scriptEntrypointNumber = 0;
318 
319  _flags = 0;
320  _nameIndex = 0;
321  _sceneNumber = 0;
322  _spriteListResourceId = 0;
323 
324  _screenDepth = 0;
325  _screenScale = 0;
326  }
327 };
328 
330 
332 
334 public:
335  //constant
336  uint16 _interactBits;
337 
338  ObjectData() {
339  _interactBits = 0;
340  }
341 };
342 
344 
346 public:
347  //constant
348  SpriteList _spriteList; // sprite list data
349 
350  ActorFrameSequences *_frames; // Actor's frames
351  ActorFrameSequences _framesContainer; // Actor's frames
352  int _frameListResourceId; // Actor's frame list resource id
353 
354  byte _speechColor; // Actor dialogue color
355  //
356  bool _inScene;
357 
358  //variables
359  uint16 _actorFlags; // dynamic flags
360  int32 _currentAction; // ActorActions type
361  int32 _facingDirection; // orientation
362  int32 _actionDirection;
363  int32 _actionCycle;
364  uint16 _targetObject;
365  const HitZone *_lastZone;
366 
367  int32 _cycleFrameSequence;
368  uint8 _cycleDelay;
369  uint8 _cycleTimeCount;
370  uint8 _cycleFlags;
371 
372  int16 _fallVelocity;
373  int16 _fallAcceleration;
374  int16 _fallPosition;
375 
376  uint8 _dragonBaseFrame;
377  uint8 _dragonStepCycle;
378  uint8 _dragonMoveType;
379 
380  int32 _frameNumber; // current frame number
381 
382  ByteArray _tileDirections;
383 
384  Common::Array<Point> _walkStepsPoints;
385 
386  int32 _walkStepsCount;
387  int32 _walkStepIndex;
388 
389  Location _finalTarget;
390  Location _partialTarget;
391  int32 _walkFrameSequence;
392 
393 public:
394  ActorData();
395 
396  void saveState(Common::OutSaveFile *out);
397  void loadState(uint32 version, Common::InSaveFile *in);
398 
399  void cycleWrap(int cycleLimit);
400  void addWalkStepPoint(const Point &point);
401  bool shareFrames() {
402  return ((_frames != NULL) && (_frames != &_framesContainer));
403  }
404 };
405 
407 
409  ActorFrameSequences _frames; // Actor's frames
410 };
411 
412 
413 struct SpeechData {
414  int speechColor[ACTOR_SPEECH_ACTORS_MAX];
415  int outlineColor[ACTOR_SPEECH_ACTORS_MAX];
416  int speechFlags;
417  const char *strings[ACTOR_SPEECH_STRING_MAX];
418  Rect speechBox;
419  Rect drawRect;
420  int stringsCount;
421  int slowModeCharIndex;
422  uint16 actorIds[ACTOR_SPEECH_ACTORS_MAX];
423  int actorsCount;
424  int sampleResourceId;
425  bool playing;
426  int playingTime;
427 
428  SpeechData() {
429  for (uint i = 0; i < ACTOR_SPEECH_ACTORS_MAX; i++) {
430  speechColor[i] = 0;
431  outlineColor[i] = 0;
432  }
433  speechFlags = 0;
434  for (uint i = 0; i < ACTOR_SPEECH_ACTORS_MAX; i++) {
435  strings[i] = nullptr;
436  }
437  // speechBox is initialized by Rect constructor
438  // drawRect is initialized by Rect constructor
439  stringsCount = 0;
440  slowModeCharIndex = 0;
441  for (uint i = 0; i < ACTOR_SPEECH_ACTORS_MAX; i++) {
442  actorIds[i] = 0;
443  }
444  actorsCount = 0;
445  sampleResourceId = 0;
446  playing = false;
447  playingTime = 0;
448  }
449 
450  FontEffectFlags getFontFlags(int i) {
451  if (outlineColor[i] != 0) {
452  return kFontOutline;
453  } else {
454  return kFontNormal;
455  }
456  }
457 };
458 
459 typedef int (*CompareFunction) (const CommonObjectDataPointer& a, const CommonObjectDataPointer& b);
460 
461 class Actor {
462  friend class IsoMap;
463  friend class SagaEngine;
464  friend class Puzzle;
465 public:
466 
467  Actor(SagaEngine *vm);
468  ~Actor();
469 
470  void cmdActorWalkTo(int argc, const char **argv);
471 
472  bool validActorId(uint16 id) {
473  return (id == ID_PROTAG) || ((id >= objectIndexToId(kGameObjectActor, 0)) && (id < objectIndexToId(kGameObjectActor, _actors.size())));
474  }
475  int actorIdToIndex(uint16 id) { return (id == ID_PROTAG) ? 0 : objectIdToIndex(id); }
476  uint16 actorIndexToId(int index) { return (index == 0) ? ID_PROTAG : objectIndexToId(kGameObjectActor, index); }
477  ActorData *getActor(uint16 actorId);
478 
479 // clarification: Obj - means game object, such Hat, Spoon etc, Object - means Actor,Obj,HitZone,StepZone
480 
481  bool validObjId(uint16 id) { return (id >= objectIndexToId(kGameObjectObject, 0)) && (id < objectIndexToId(kGameObjectObject, _objs.size())); }
482  int objIdToIndex(uint16 id) { return objectIdToIndex(id); }
483  uint16 objIndexToId(int index) { return objectIndexToId(kGameObjectObject, index); }
484  ObjectData *getObj(uint16 objId);
485 
486  int getObjectScriptEntrypointNumber(uint16 id) {
487  int objectType;
488  objectType = objectTypeId(id);
489  if (!(objectType & (kGameObjectObject | kGameObjectActor))) {
490  error("Actor::getObjectScriptEntrypointNumber wrong id 0x%X", id);
491  }
492  return (objectType == kGameObjectObject) ? getObj(id)->_scriptEntrypointNumber : getActor(id)->_scriptEntrypointNumber;
493  }
494  int getObjectFlags(uint16 id) {
495  int objectType;
496  objectType = objectTypeId(id);
497  if (!(objectType & (kGameObjectObject | kGameObjectActor))) {
498  error("Actor::getObjectFlags wrong id 0x%X", id);
499  }
500  return (objectType == kGameObjectObject) ? getObj(id)->_flags : getActor(id)->_flags;
501  }
502 
503  void direct(int msec);
504  void drawActors();
505  void updateActorsScene(int actorsEntrance); // calls from scene loading to update Actors info
506 
507  void drawSpeech();
508 
509 #ifdef ACTOR_DEBUG
510  void drawPathTest();
511 #endif
512 
513  uint16 hitTest(const Point &testPoint, bool skipProtagonist);
514  void takeExit(uint16 actorId, const HitZone *hitZone);
515  bool actorEndWalk(uint16 actorId, bool recurse);
516  bool actorWalkTo(uint16 actorId, const Location &toLocation);
517  int getFrameType(ActorFrameTypes frameType);
518  ActorFrameRange *getActorFrameRange(uint16 actorId, int frameType);
519  void actorFaceTowardsPoint(uint16 actorId, const Location &toLocation);
520  void actorFaceTowardsObject(uint16 actorId, uint16 objectId);
521 
522  void realLocation(Location &location, uint16 objectId, uint16 walkFlags);
523 
524 // speech
525  void actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags);
526  void nonActorSpeech(const Common::Rect &box, const char **strings, int stringsCount, int sampleResourceId, int speechFlags);
527  void simulSpeech(const char *string, uint16 *actorIds, int actorIdsCount, int speechFlags, int sampleResourceId);
528  void setSpeechColor(int speechColor, int outlineColor) {
529  _activeSpeech.speechColor[0] = speechColor;
530  _activeSpeech.outlineColor[0] = outlineColor;
531  }
532  void abortAllSpeeches();
533  void abortSpeech();
534  bool isSpeaking() {
535  return _activeSpeech.stringsCount > 0;
536  }
537 
538  int isForcedTextShown() {
539  return _activeSpeech.speechFlags & kSpeakForceText;
540  }
541 
542  void saveState(Common::OutSaveFile *out);
543  void loadState(Common::InSaveFile *in);
544 
545  void setProtagState(int state);
546  int getProtagState() { return _protagState; }
547 
548  void loadActorList(int protagonistIdx, int actorCount, int actorsResourceID,
549  int protagStatesCount, int protagStatesResourceID);
550  void loadObjList(int objectCount, int objectsResourceID);
551 
552 protected:
553  friend class Script;
554  void loadActorResources(ActorData *actor);
555  void loadFrameList(int frameListResourceId, ActorFrameSequences &frames);
556 private:
557  void stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit, bool stopped);
558  void loadActorSpriteList(ActorData *actor);
559 
560  void drawOrderListAdd(const CommonObjectDataPointer& element, CompareFunction compareFunction);
561  void createDrawOrderList();
562  bool calcScreenPosition(CommonObjectData *commonObjectData);
563  bool getSpriteParams(CommonObjectData *commonObjectData, int &frameNumber, SpriteList *&spriteList);
564 
565  bool followProtagonist(ActorData *actor);
566  void findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint);
567  void handleSpeech(int msec);
568  void handleActions(int msec, bool setup);
569  bool validPathCellPoint(const Point &testPoint) {
570  return !((testPoint.x < 0) || (testPoint.x >= _xCellCount) ||
571  (testPoint.y < 0) || (testPoint.y >= _yCellCount));
572  }
573  void setPathCell(const Point &testPoint, int8 value) {
574 #ifdef ACTOR_DEBUG
575  if (!validPathCellPoint(testPoint)) {
576  error("Actor::setPathCell wrong point");
577  }
578 #endif
579  _pathCell[testPoint.x + testPoint.y * _xCellCount] = value;
580  }
581  int8 getPathCell(const Point &testPoint) {
582 #ifdef ACTOR_DEBUG
583  if (!validPathCellPoint(testPoint)) {
584  error("Actor::getPathCell wrong point");
585  }
586 #endif
587  return _pathCell[testPoint.x + testPoint.y * _xCellCount];
588  }
589  bool scanPathLine(const Point &point1, const Point &point2);
590  int fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint);
591  void setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint);
592  void pathToNode();
593  void condenseNodeList();
594  void removeNodes();
595  void nodeToPath();
596  void removePathPoints();
597  bool validFollowerLocation(const Location &location);
598  void moveDragon(ActorData *actor);
599 
600 
601 protected:
602 //constants
603  ActorDataArray _actors;
604 
605  ObjectDataArray _objs;
606 
607  SagaEngine *_vm;
608  ResourceContext *_actorContext;
609 
610  int _lastTickMsec;
611  CommonObjectOrderList _drawOrderList;
612 
613 //variables
614 public:
615  ActorData *_centerActor;
616  ActorData *_protagonist;
617  int _handleActionDiv;
618 
619  Rect _speechBoxScript;
620 
621  StringsTable _objectsStrings;
622  StringsTable _actorsStrings;
623 
624 protected:
625  SpeechData _activeSpeech;
626  int _protagState;
627  bool _dragonHunt;
628 
629 private:
630  Common::Array<ProtagStateData> _protagStates;
631 
632 //path stuff
633  struct PathNode {
634  Point point;
635  int link;
636 
637  PathNode() : link(0) {}
638  PathNode(const Point &p) : point(p), link(0) {}
639  PathNode(const Point &p, int l) : point(p), link(l) {}
640  };
642 
643  Rect _barrierList[ACTOR_BARRIERS_MAX];
644  int _barrierCount;
645  Common::Array<int8> _pathCell;
646 
647  int _xCellCount;
648  int _yCellCount;
649  Rect _pathRect;
650 
651  PointList _pathList;
652  uint _pathListIndex;
653 
654  PathNodeList _pathNodeList;
655 
656 public:
657 #ifdef ACTOR_DEBUG
658 #ifndef SAGA_DEBUG
659  #error You must also define SAGA_DEBUG
660 #endif
661 //path debug - use with care
662  struct DebugPoint {
663  Point point;
664  byte color;
665 
666  DebugPoint() : color(0) {}
667 
668  DebugPoint(const Point &p, byte c): point(p), color(c) {}
669  };
670 
671  Common::Array<DebugPoint> _debugPoints;
672  uint _debugPointsCount;
673  // we still need this trick to speedup debug points addition
674  void addDebugPoint(const Point &point, byte color) {
675  if (_debugPointsCount < _debugPoints.size()) {
676  _debugPoints[_debugPointsCount].point = point;
677  _debugPoints[_debugPointsCount].color = color;
678  } else {
679  _debugPoints.push_back(DebugPoint(point, color));
680  }
681  ++_debugPointsCount;
682  }
683 #endif
684 };
685 
686 } // End of namespace Saga
687 
688 #endif
Definition: resource.h:105
Definition: saga.h:497
uint16 readUint16LE()
Definition: stream.h:459
Definition: actor.h:461
FORCEINLINE int32 readSint32LE()
Definition: stream.h:555
Definition: savefile.h:54
Definition: isomap.h:149
Definition: actor.h:191
Definition: saga.h:356
Definition: rect.h:144
Definition: stream.h:745
Definition: saga.h:464
Definition: objectmap.h:30
Definition: script.h:272
Definition: actor.h:186
void push_back(const T &element)
Definition: array.h:180
Definition: actor.h:34
void writeUint16LE(uint16 value)
Definition: stream.h:152
Definition: puzzle.h:37
Definition: rect.h:45
Definition: actor.h:333
size_type size() const
Definition: array.h:315
Definition: actor.h:199
Definition: actor.h:408
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
Definition: actor.h:273
Definition: actor.h:345
Definition: actor.h:180
FORCEINLINE int16 readSint16LE()
Definition: stream.h:543
Definition: actor.h:413
int16 x
Definition: rect.h:46
FORCEINLINE void writeSint16LE(int16 value)
Definition: stream.h:194
int16 y
Definition: rect.h:47
Definition: stream.h:385
T MAX(T a, T b)
Definition: util.h:62
FORCEINLINE void writeSint32LE(int32 value)
Definition: stream.h:200
T ABS(T x)
Definition: util.h:56