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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifndef SAGA_SAGA_H
24 #define SAGA_SAGA_H
25
26 #include "engines/engine.h"
27
28 #include "common/array.h"
29 #include "common/random.h"
30 #include "common/memstream.h"
31 #include "common/textconsole.h"
32
33 #include "saga/gfx.h"
34
35 struct ADGameFileDescription;
36
37 /**
38 * This is the namespace of the SAGA engine.
39 *
40 * Status of this engine:
41 *
42 * This engine contains 2 main engine generations, SAGA and SAGA2
43 *
44 * SAGA status: complete
45 *
46 * SAGA2 status: in early stages of development, no recent activity. Contact sev
47 * if you want to work on it, since we have some original source codes.
48 *
49 * Games using this engine:
50 *
51 * SAGA:
52 * - Inherit the Earth
53 * - I Have No Mouth And I Must Scream
54 *
55 * SAGA2:
56 * - Dinotopia
57 * - Faery Tale Adventure II: Halls of the Dead
58 *
59 */
60 namespace Saga {
61
62 class SndRes;
63 class Sound;
64 class Music;
65 class Anim;
66 class Render;
67 class IsoMap;
68 class Gfx;
69 class Script;
70 class Actor;
71 class Font;
72 class Sprite;
73 class Scene;
74 class Interface;
75 class Console;
76 class Events;
77 class PalAnim;
78 class Puzzle;
79 class Resource;
80
81 class ResourceContext;
82
83 // #define SAGA_DEBUG 1 // define for test functions
84 #define SAGA_IMAGE_DATA_OFFSET 776
85 #define SAGA_IMAGE_HEADER_LEN 8
86
87 // Note that IHNM has a smaller save title size than ITE
88 // We allocate the ITE save title size in savegames, to
89 // preserve savegame backwards compatibility. We only check
90 // for IHNM's save title during text input
91 #define SAVE_TITLE_SIZE 28
92 #define TITLESIZE 80
93 #define IHNM_SAVE_TITLE_SIZE 22
94 #define MAX_SAVES 96
95 #define MAX_FILE_NAME 256
96
97 #define ID_NOTHING 0
98 #define ID_PROTAG 1
99 #define OBJECT_TYPE_SHIFT 13
100 #define OBJECT_TYPE_MASK ((1 << OBJECT_TYPE_SHIFT) - 1)
101
102 #define IHNM_OBJ_PROFILE 0x4000
103
104 #define memoryError(Place) error("%s Memory allocation error.", Place)
105
106 enum ERRORCODE {
107 FAILURE = -1,
108 SUCCESS = 0
109 };
110
111 enum GameIds {
112 GID_ITE = 0,
113 GID_IHNM = 1,
114 GID_DINO = 2,
115 GID_FTA2 = 3
116 };
117
118 enum GameFileTypes {
119 // Common
120 GAME_RESOURCEFILE = 1 << 0, // Game resources
121 GAME_SCRIPTFILE = 1 << 1, // Game scripts
122 GAME_SOUNDFILE = 1 << 2, // SFX (also contains voices and MIDI music in SAGA 2 games)
123 GAME_VOICEFILE = 1 << 3, // Voices (also contains SFX in the ITE floppy version)
124 // ITE specific
125 GAME_DIGITALMUSICFILE = 1 << 4, // ITE digital music, added by Wyrmkeep
126 GAME_MACBINARY = 1 << 5, // ITE Mac CD Guild
127 GAME_DEMOFILE = 1 << 6, // Early ITE demo
128 GAME_SWAPENDIAN = 1 << 7, // Used to identify the BE voice file in the ITE combined version
129 // IHNM specific
130 GAME_MUSICFILE_FM = 1 << 8, // IHNM
131 GAME_MUSICFILE_GM = 1 << 9, // IHNM, ITE Mac CD Guild
132 GAME_PATCHFILE = 1 << 10, // IHNM patch file (patch.re_/patch.res)
133 // SAGA 2 (Dinotopia, FTA2)
134 GAME_IMAGEFILE = 1 << 11, // Game images
135 GAME_OBJRESOURCEFILE = 1 << 12 // Game object data
136 };
137
138 enum GameFeatures {
139 GF_ITE_FLOPPY = 1 << 0,
140 GF_ITE_DOS_DEMO = 1 << 1,
141 GF_EXTRA_ITE_CREDITS = 1 << 2,
142 GF_8BIT_UNSIGNED_PCM = 1 << 3,
143 GF_IHNM_COLOR_FIX = 1 << 4
144 };
145
146 enum VerbTypeIds {
147 kVerbITENone = 0,
148 kVerbITEPickUp = 1,
149 kVerbITELookAt = 2,
150 kVerbITEWalkTo = 3,
151 kVerbITETalkTo = 4,
152 kVerbITEOpen = 5,
153 kVerbITEClose = 6,
154 kVerbITEGive = 7,
155 kVerbITEUse = 8,
156 kVerbITEOptions = 9,
157 kVerbITEEnter = 10,
158 kVerbITELeave = 11,
159 kVerbITEBegin = 12,
160 kVerbITEWalkOnly = 13,
161 kVerbITELookOnly = 14,
162
163
164 kVerbIHNMNone = 0,
165 kVerbIHNMWalk = 1,
166 kVerbIHNMLookAt = 2,
167 kVerbIHNMTake = 3,
168 kVerbIHNMUse = 4,
169 kVerbIHNMTalkTo = 5,
170 kVerbIHNMSwallow = 6,
171 kVerbIHNMGive = 7,
172 kVerbIHNMPush = 8,
173 kVerbIHNMOptions = 9,
174 kVerbIHNMEnter = 10,
175 kVerbIHNMLeave = 11,
176 kVerbIHNMBegin = 12,
177 kVerbIHNMWalkOnly = 13,
178 kVerbIHNMLookOnly = 14,
179
180 kVerbTypeIdsMax = kVerbITELookOnly + 1
181 };
182
183 enum PanelButtonType {
184 kPanelButtonVerb = 1 << 0,
185 kPanelButtonArrow = 1 << 1,
186 kPanelButtonConverseText = 1 << 2,
187 kPanelButtonInventory = 1 << 3,
188
189 kPanelButtonOption = 1 << 4,
190 kPanelButtonOptionSlider = 1 << 5,
191 kPanelButtonOptionSaveFiles = 1 << 6,
192 kPanelButtonOptionText = 1 << 7,
193
194 kPanelButtonQuit = 1 << 8,
195 kPanelButtonQuitText = 1 << 9,
196
197 kPanelButtonLoad = 1 << 10,
198 kPanelButtonLoadText = 1 << 11,
199
200 kPanelButtonSave = 1 << 12,
201 kPanelButtonSaveText = 1 << 13,
202 kPanelButtonSaveEdit = 1 << 14,
203
204 kPanelButtonProtectText = 1 << 15,
205 kPanelButtonProtectEdit = 1 << 16,
206
207 kPanelAllButtons = 0xFFFFF
208 };
209
210 enum TextStringIds {
211 kTextPickUp,
212 kTextLookAt,
213 kTextWalkTo,
214 kTextTalkTo,
215 kTextOpen,
216 kTextClose,
217 kTextGive,
218 kTextUse,
219
220 kTextOptions,
221 kTextTest,
222 kTextDemo,
223 kTextHelp,
224 kTextQuitGame,
225 kTextFast,
226 kTextSlow,
227 kTextOn,
228 kTextOff,
229 kTextContinuePlaying,
230 kTextLoad,
231 kTextSave,
232 kTextGameOptions,
233 kTextReadingSpeed,
234 kTextMusic,
235 kTextSound,
236 kTextCancel,
237 kTextQuit,
238 kTextOK,
239 kTextMid,
240 kTextClick,
241 kText10Percent,
242 kText20Percent,
243 kText30Percent,
244 kText40Percent,
245 kText50Percent,
246 kText60Percent,
247 kText70Percent,
248 kText80Percent,
249 kText90Percent,
250 kTextMax,
251 kTextQuitTheGameQuestion,
252 kTextLoadSuccessful,
253 kTextEnterSaveGameName,
254 kTextGiveTo,
255 kTextUseWidth,
256 kTextNewSave,
257 kTextICantPickup,
258 kTextNothingSpecial,
259 kTextNoPlaceToOpen,
260 kTextNoOpening,
261 kTextDontKnow,
262 kTextShowDialog,
263 kTextEnterProtectAnswer,
264 kTextVoices,
265 kTextText,
266 kTextAudio,
267 kTextBoth,
268 kTextLoadSavedGame
269 };
270
271 struct GameResourceDescription {
272 uint32 sceneLUTResourceId;
273 uint32 moduleLUTResourceId;
274 uint32 mainPanelResourceId;
275 uint32 conversePanelResourceId;
276 uint32 optionPanelResourceId;
277 uint32 mainSpritesResourceId;
278 uint32 mainPanelSpritesResourceId;
279 uint32 mainStringsResourceId;
280 // ITE specific resources
281 uint32 actorsStringsResourceId;
282 uint32 defaultPortraitsResourceId;
283 // IHNM specific resources
284 uint32 optionPanelSpritesResourceId;
285 uint32 warningPanelResourceId;
286 uint32 warningPanelSpritesResourceId;
287 uint32 psychicProfileResourceId;
288 };
289
290 struct GameFontDescription {
291 uint32 fontResourceId;
292 };
293
294 struct GameDisplayInfo;
295
296 struct GamePatchDescription {
297 const char *fileName;
298 uint16 fileType;
299 uint32 resourceId;
300 };
301
302 struct SAGAGameDescription;
303
304 enum GameObjectTypes {
305 kGameObjectNone = 0,
306 kGameObjectActor = 1,
307 kGameObjectObject = 2,
308 kGameObjectHitZone = 3,
309 kGameObjectStepZone = 4
310 };
311
312 enum ScriptTimings {
313 kScriptTimeTicksPerSecond = (728L/10L),
314 kRepeatSpeedTicks = (728L/10L)/3,
315 kNormalFadeDuration = 320, // 64 steps, 5 msec each
316 kQuickFadeDuration = 64, // 64 steps, 1 msec each
317 kPuzzleHintTime = 30000000L // 30 secs. used in timer
318 };
319
320 enum Directions {
321 kDirUp = 0,
322 kDirUpRight = 1,
323 kDirRight = 2,
324 kDirDownRight = 3,
325 kDirDown = 4,
326 kDirDownLeft = 5,
327 kDirLeft = 6,
328 kDirUpLeft = 7
329 };
330
331 enum HitZoneFlags {
332 kHitZoneEnabled = (1 << 0), // Zone is enabled
333 kHitZoneExit = (1 << 1), // Causes char to exit
334
335 // The following flag causes the zone to act differently.
336 // When the actor hits the zone, it will immediately begin walking
337 // in the specified direction, and the actual specified effect of
338 // the zone will be delayed until the actor leaves the zone.
339 kHitZoneAutoWalk = (1 << 2),
340
341 // When set on a hit zone, this causes the character not to walk
342 // to the object (but they will look at it).
343 kHitZoneNoWalk = (1 << 2),
344
345 // zone activates only when character stops walking
346 kHitZoneTerminus = (1 << 3),
347
348 // Hit zones only - when the zone is clicked on it projects the
349 // click point downwards from the middle of the zone until it
350 // reaches the lowest point in the zone.
351 kHitZoneProject = (1 << 3)
352 };
353
354 struct ImageHeader {
355 int width;
356 int height;
357 };
358
359 struct StringsTable {
360 Common::Array<char> buffer;
361 Common::Array<char *> strings;
362
getStringStringsTable363 const char *getString(uint index) const {
364 if (strings.size() <= index) {
365 // This occurs at the end of Ted's chapter, right after the ending cutscene
366 warning("StringsTable::getString wrong index 0x%X (%d)", index, strings.size());
367 return "";
368 }
369 return strings[index];
370 }
371
clearStringsTable372 void clear() {
373 strings.clear();
374 buffer.clear();
375 }
376 };
377
378 typedef Common::Array<Point> PointList;
379
380 enum ColorId {
381 kITEColorTransBlack = 0x00,
382 kITEColorBrightWhite = 0x01,
383 kITEColorWhite = 0x02,
384 kITEColorLightGrey = 0x04,
385 kITEColorGrey = 0x0a,
386 kITEColorDarkGrey = 0x0b,
387 kITEColorDarkGrey0C = 0x0C,
388 kITEColorBlack = 0x0f,
389 kITEColorRed = 0x65,
390 kITEColorDarkBlue8a = 0x8a,
391 kITEColorBlue89 = 0x89,
392 kITEColorLightBlue92 = 0x92,
393 kITEColorBlue = 0x93,
394 kITEColorLightBlue94 = 0x94,
395 kITEColorLightBlue96 = 0x96,
396 kITEColorGreen = 0xba
397 };
398
399 enum KnownColor {
400 kKnownColorTransparent,
401 kKnownColorBrightWhite,
402 kKnownColorWhite,
403 kKnownColorBlack,
404
405 kKnownColorSubtitleTextColor,
406 kKnownColorVerbText,
407 kKnownColorVerbTextShadow,
408 kKnownColorVerbTextActive
409 };
410
411 struct SaveFileData {
412 char name[SAVE_TITLE_SIZE];
413 uint slotNumber;
414 };
415
416 struct SaveGameHeader {
417 uint32 type;
418 uint32 size;
419 uint32 version;
420 char name[SAVE_TITLE_SIZE];
421 };
422
objectTypeId(uint16 objectId)423 inline int objectTypeId(uint16 objectId) {
424 return objectId >> OBJECT_TYPE_SHIFT;
425 }
426
objectIdToIndex(uint16 objectId)427 inline int objectIdToIndex(uint16 objectId) {
428 return OBJECT_TYPE_MASK & objectId;
429 }
430
objectIndexToId(int type,int index)431 inline uint16 objectIndexToId(int type, int index) {
432 return (type << OBJECT_TYPE_SHIFT) | (OBJECT_TYPE_MASK & index);
433 }
434
435 class ByteArray : public Common::Array<byte> {
436 public:
437 /**
438 * Return a pointer to the start of the buffer underlying this byte array,
439 * or NULL if the buffer is empty.
440 */
getBuffer()441 byte *getBuffer() {
442 return empty() ? NULL : &front();
443 }
444
getBuffer()445 const byte *getBuffer() const {
446 return empty() ? NULL : &front();
447 }
448
assign(const ByteArray & src)449 void assign(const ByteArray &src) {
450 resize(src.size());
451 if (!empty()) {
452 memcpy(&front(), &src.front(), size());
453 }
454 }
455 };
456
457 class ByteArrayReadStreamEndian : public Common::MemoryReadStreamEndian {
458 public:
459 ByteArrayReadStreamEndian(const ByteArray & byteArray, bool bigEndian = false)
460 : Common::MemoryReadStreamEndian(byteArray.getBuffer(), byteArray.size(), bigEndian) {
461 }
462 };
463
464 class SagaEngine : public Engine {
465 friend class Scene;
466
467 public:
468 // Engine APIs
469 virtual Common::Error run();
470 bool hasFeature(EngineFeature f) const;
471 void syncSoundSettings();
472 void pauseEngineIntern(bool pause);
473
474 GUI::Debugger *getDebugger();
475
476 SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc);
477 ~SagaEngine();
478
479 void save(const char *fileName, const char *saveName);
480 void load(const char *fileName);
getCurrentLoadVersion()481 uint32 getCurrentLoadVersion() const {
482 return _saveHeader.version;
483 }
484 void fillSaveList();
485 char *calcSaveFileName(uint slotNumber);
486
487 SaveFileData *getSaveFile(uint idx);
488 uint getNewSaveSlotNumber() const;
489 bool locateSaveFile(char *saveName, uint &titleNumber);
isSaveListFull()490 bool isSaveListFull() const {
491 return _saveFilesCount == MAX_SAVES;
492 }
getSaveFilesCount()493 uint getSaveFilesCount() const {
494 return isSaveListFull() ? _saveFilesCount : _saveFilesCount + 1;
495 }
496
isIHNMDemo()497 bool isIHNMDemo() const { return _isIHNMDemo; }
498
499 int16 _framesEsc;
500
501 uint32 _globalFlags;
502 int16 _ethicsPoints[8];
503 int _spiritualBarometer;
504
505 int _soundVolume;
506 int _musicVolume;
507 int _speechVolume;
508 bool _subtitlesEnabled;
509 bool _voicesEnabled;
510 bool _voiceFilesExist;
511 int _readingSpeed;
512
513 bool _copyProtection;
514 bool _musicWasPlaying;
515 bool _isIHNMDemo;
516 bool _hasITESceneSubstitutes;
517
518 SndRes *_sndRes;
519 Sound *_sound;
520 Music *_music;
521 Anim *_anim;
522 Render *_render;
523 IsoMap *_isoMap;
524 Gfx *_gfx;
525 Script *_script;
526 Actor *_actor;
527 Font *_font;
528 Sprite *_sprite;
529 Scene *_scene;
530 Interface *_interface;
531 Console *_console;
532 Events *_events;
533 PalAnim *_palanim;
534 Puzzle *_puzzle;
535 Resource *_resource;
536
537
538 // Random number generator
539 Common::RandomSource _rnd;
540
541 private:
542 bool decodeBGImageRLE(const byte *inbuf, size_t inbuf_len, ByteArray &outbuf);
543 void flipImage(byte *imageBuffer, int columns, int scanlines);
544 void unbankBGImage(byte *dest_buf, const byte *src_buf, int columns, int scanlines);
545 uint32 _previousTicks;
546
547 public:
548 bool decodeBGImage(const ByteArray &imageData, ByteArray &outputBuffer, int *w, int *h, bool flip = false);
getImagePal(const ByteArray & imageData)549 const byte *getImagePal(const ByteArray &imageData) {
550 if (imageData.size() <= SAGA_IMAGE_HEADER_LEN) {
551 return NULL;
552 }
553
554 return &imageData.front() + SAGA_IMAGE_HEADER_LEN;
555 }
556 void loadStrings(StringsTable &stringsTable, const ByteArray &stringsData);
557
558 const char *getObjectName(uint16 objectId) const;
559 public:
560 int processInput();
561 Point mousePos() const;
562
getMouseClickCount()563 int getMouseClickCount() const {
564 return _mouseClickCount;
565 }
566
incrementMouseClickCount()567 void incrementMouseClickCount() {
568 _mouseClickCount++;
569 }
570
resetMouseClickCount()571 void resetMouseClickCount() {
572 _mouseClickCount = 0;
573 }
574
leftMouseButtonPressed()575 bool leftMouseButtonPressed() const {
576 return _leftMouseButtonPressed;
577 }
578
rightMouseButtonPressed()579 bool rightMouseButtonPressed() const {
580 return _rightMouseButtonPressed;
581 }
582
mouseButtonPressed()583 bool mouseButtonPressed() const {
584 return _leftMouseButtonPressed || _rightMouseButtonPressed;
585 }
586
ticksToMSec(int tick)587 inline int ticksToMSec(int tick) const {
588 return tick * 1000 / kScriptTimeTicksPerSecond;
589 }
590
591 private:
592 uint _saveFilesCount;
593 SaveFileData _saveFiles[MAX_SAVES];
594 SaveGameHeader _saveHeader;
595
596 bool _leftMouseButtonPressed;
597 bool _rightMouseButtonPressed;
598 int _mouseClickCount;
599
600 //current game description
601 int _gameNumber;
602 const SAGAGameDescription *_gameDescription;
603 Common::String _gameTitle;
604 Common::Rect _displayClip;
605
606 public:
607 int32 _frameCount;
608
609 public:
610 bool initGame();
611
612 bool isBigEndian() const;
613 bool isMacResources() const;
isSaga2()614 bool isSaga2() const { return getGameId() == GID_DINO || getGameId() == GID_FTA2; }
615 const GameResourceDescription *getResourceDescription() const;
616
617 const GameFontDescription *getFontDescription(int index) const;
618 int getFontsCount() const;
619
620 int getGameId() const;
621 uint32 getFeatures() const;
622 Common::Language getLanguage() const;
623 Common::Platform getPlatform() const;
624 int getGameNumber() const;
625 int getStartSceneNumber() const;
626
627 const GamePatchDescription *getPatchDescriptions() const;
628
629 const ADGameFileDescription *getFilesDescriptions() const;
630
getDisplayClip()631 const Common::Rect &getDisplayClip() const { return _displayClip;}
632 Common::Error loadGameState(int slot);
633 Common::Error saveGameState(int slot, const Common::String &desc);
634 bool canLoadGameStateCurrently();
635 bool canSaveGameStateCurrently();
636 const GameDisplayInfo &getDisplayInfo();
637
638 const char *getTextString(int textStringId);
639 void getExcuseInfo(int verb, const char *&textString, int &soundResourceId);
640
641 private:
642
643 public:
644 ColorId KnownColor2ColorId(KnownColor knownColor);
645 void setTalkspeed(int talkspeed);
646 int getTalkspeed() const;
647 };
648
649 } // End of namespace Saga
650
651 #endif
652