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
34namespace Saga {
35
36class 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
72enum ActorDirections {
73 kDirectionRight = 0,
74 kDirectionLeft = 1,
75 kDirectionUp = 2,
76 kDirectionDown = 3
77};
78
79enum 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
95enum 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
113enum SpeechFlags {
114 kSpeakNoAnimate = 1,
115 kSpeakAsync = 2,
116 kSpeakSlow = 4,
117 kSpeakForceText = 8
118};
119
120enum 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
132static 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
143enum 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
158enum PathCellType {
159 kPathCellEmpty = -1,
160 //kDirUp = 0 .... kDirUpLeft = 7
161 kPathCellBarrier = 0x57
162};
163
164enum 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
197uint pathLine(PointList &pointList, uint idx, const Point &point1, const Point &point2);
198
199struct 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
274public:
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
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
334public:
335 //constant
336 uint16 _interactBits;
337
338 ObjectData() {
339 _interactBits = 0;
340 }
341};
342
344
346public:
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
393public:
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
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
459typedef int (*CompareFunction) (const CommonObjectDataPointer& a, const CommonObjectDataPointer& b);
460
461class Actor {
462 friend class IsoMap;
463 friend class SagaEngine;
464 friend class Puzzle;
465public:
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
552protected:
553 friend class Script;
554 void loadActorResources(ActorData *actor);
555 void loadFrameList(int frameListResourceId, ActorFrameSequences &frames);
556private:
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
601protected:
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
614public:
615 ActorData *_centerActor;
616 ActorData *_protagonist;
617 int _handleActionDiv;
618
619 Rect _speechBoxScript;
620
621 StringsTable _objectsStrings;
622 StringsTable _actorsStrings;
623
624protected:
625 SpeechData _activeSpeech;
626 int _protagState;
627 bool _dragonHunt;
628
629private:
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
656public:
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
size_type size() const
Definition: array.h:316
void push_back(const T &element)
Definition: array.h:181
Definition: savefile.h:54
Definition: stream.h:385
uint16 readUint16LE()
Definition: stream.h:459
Definition: stream.h:745
void writeUint16LE(uint16 value)
Definition: stream.h:152
FORCEINLINE void writeSint16LE(int16 value)
Definition: stream.h:194
FORCEINLINE void writeSint32LE(int32 value)
Definition: stream.h:200
Definition: actor.h:345
Definition: actor.h:461
Definition: saga.h:464
Definition: actor.h:273
Definition: objectmap.h:30
Definition: isomap.h:149
Definition: actor.h:333
Definition: puzzle.h:37
Definition: resource.h:105
Definition: saga.h:497
Definition: script.h:272
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
T ABS(T x)
Definition: util.h:60
T MAX(T a, T b)
Definition: util.h:66
Definition: actor.h:34
T y
Definition: rect.h:49
T x
Definition: rect.h:48
Definition: rect.h:144
Definition: rect.h:536
Definition: actor.h:186
Definition: actor.h:191
Definition: actor.h:199
Definition: actor.h:180
Definition: actor.h:408
Definition: actor.h:413
Definition: saga.h:356