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 AGI_AGI_H
24 #define AGI_AGI_H
25 
26 #include "common/scummsys.h"
27 #include "common/error.h"
28 #include "common/util.h"
29 #include "common/file.h"
30 #include "common/keyboard.h"
31 #include "common/rect.h"
32 #include "common/rendermode.h"
33 #include "common/stack.h"
34 #include "common/str.h"
35 #include "common/system.h"
36 
37 #include "engines/engine.h"
38 
39 #include "gui/debugger.h"
40 
41 // AGI resources
42 #include "agi/console.h"
43 #include "agi/view.h"
44 #include "agi/picture.h"
45 #include "agi/logic.h"
46 #include "agi/sound.h"
47 #include "agi/detection.h"
48 
49 namespace Common {
50 class RandomSource;
51 }
52 
53 /**
54  * This is the namespace of the AGI engine.
55  *
56  * Status of this engine: ???
57  *
58  * Games using this engine:
59  * - Early Sierra adventure games
60  * - many fan made games
61  * - Mickey's Space Adventure (Pre-AGI)
62  * - Winnie the Pooh in the Hundred Acre Wood (Pre-AGI)
63  * - Troll's Tale (Pre-AGI)
64  */
65 namespace Agi {
66 
67 typedef signed int Err;
68 
69 //
70 // Version and other definitions
71 //
72 
73 #define TITLE       "AGI engine"
74 
75 #define DIR_        "dir"
76 #define LOGDIR      "logdir"
77 #define PICDIR      "picdir"
78 #define VIEWDIR     "viewdir"
79 #define SNDDIR      "snddir"
80 #define OBJECTS     "object"
81 #define WORDS       "words.tok"
82 
83 #define MAX_DIRECTORY_ENTRIES      256
84 #define MAX_CONTROLLERS            256
85 #define MAX_VARS                   256
86 #define MAX_FLAGS                  (256 >> 3)
87 #define SCREENOBJECTS_MAX          255        // KQ3 uses o255!
88 #define SCREENOBJECTS_EGO_ENTRY    0          // first entry is ego
89 #define MAX_WORDS                  20
90 #define MAX_STRINGS                24         // MAX_STRINGS + 1 used for get.num
91 #define MAX_STRINGLEN              40
92 #define MAX_CONTROLLER_KEYMAPPINGS 39
93 
94 #define SAVEDGAME_DESCRIPTION_LEN 30
95 
96 #define _EMPTY       0xfffff
97 #define EGO_OWNED    0xff
98 #define EGO_OWNED_V1 0xf9
99 
100 #define CRYPT_KEY_SIERRA    "Avis Durgan"
101 #define CRYPT_KEY_AGDS      "Alex Simkin"
102 
103 #define ADD_PIC  1
104 #define ADD_VIEW 2
105 
106 #define CMD_BSIZE 12
107 
108 enum {
109 	NO_GAMEDIR = 0,
110 	GAMEDIR
111 };
112 
113 enum AGIErrors {
114 	errOK = 0,
115 	errDoNothing,
116 	errBadCLISwitch,
117 	errInvalidAGIFile,
118 	errBadFileOpen,
119 	errNotEnoughMemory,
120 	errBadResource,
121 	errUnknownAGIVersion,
122 	errNoLoopsInView,
123 	errViewDataError,
124 	errNoGameList,
125 	errIOError,
126 
127 	errUnk = 127
128 };
129 
130 enum kDebugLevels {
131 	kDebugLevelMain =      1 << 0,
132 	kDebugLevelResources = 1 << 1,
133 	kDebugLevelSprites =   1 << 2,
134 	kDebugLevelInventory = 1 << 3,
135 	kDebugLevelInput =     1 << 4,
136 	kDebugLevelMenu =      1 << 5,
137 	kDebugLevelScripts =   1 << 6,
138 	kDebugLevelSound =     1 << 7,
139 	kDebugLevelText =      1 << 8,
140 	kDebugLevelSavegame =  1 << 9
141 };
142 
143 /**
144  * AGI resources.
145  */
146 enum {
147 	RESOURCETYPE_LOGIC = 1,
148 	RESOURCETYPE_SOUND,
149 	RESOURCETYPE_VIEW,
150 	RESOURCETYPE_PICTURE
151 };
152 
153 enum {
154 	RES_LOADED                 = 0x01,
155 	RES_COMPRESSED             = 0x40,
156 	RES_PICTURE_V3_NIBBLE_PARM = 0x80  // Flag that gets set for picture resources,
157 	                                   // which use a nibble instead of a byte as F0+F2 parameters
158 };
159 
160 enum {
161 	lCOMMAND_MODE = 1,
162 	lTEST_MODE
163 };
164 
165 struct gameIdList {
166 	gameIdList *next;
167 	uint32 version;
168 	uint32 crc;
169 	char *gName;
170 	char *switches;
171 };
172 
173 struct Mouse {
174 	int button;
175 	Common::Point pos;
176 
MouseMouse177 	Mouse() : button(0) {}
178 };
179 
180 // Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable).
181 enum AgiMouseButton {
182 	kAgiMouseButtonUp,    // Mouse button is up (not pressed)
183 	kAgiMouseButtonLeft,  // Left mouse button
184 	kAgiMouseButtonRight, // Right mouse button
185 	kAgiMouseButtonMiddle // Middle mouse button
186 };
187 
188 /**
189  * AGI variables.
190  */
191 enum {
192 	VM_VAR_CURRENT_ROOM = 0,        // 0
193 	VM_VAR_PREVIOUS_ROOM,           // 1
194 	VM_VAR_BORDER_TOUCH_EGO,        // 2
195 	VM_VAR_SCORE,                   // 3
196 	VM_VAR_BORDER_CODE,             // 4
197 	VM_VAR_BORDER_TOUCH_OBJECT,     // 5
198 	VM_VAR_EGO_DIRECTION,           // 6
199 	VM_VAR_MAX_SCORE,               // 7
200 	VM_VAR_FREE_PAGES,              // 8
201 	VM_VAR_WORD_NOT_FOUND,          // 9
202 	VM_VAR_TIME_DELAY,              // 10
203 	VM_VAR_SECONDS,                 // 11
204 	VM_VAR_MINUTES,                 // 12
205 	VM_VAR_HOURS,                   // 13
206 	VM_VAR_DAYS,                    // 14
207 	VM_VAR_JOYSTICK_SENSITIVITY,    // 15
208 	VM_VAR_EGO_VIEW_RESOURCE,       // 16
209 	VM_VAR_AGI_ERROR_CODE,          // 17
210 	VM_VAR_AGI_ERROR_INFO,          // 18
211 	VM_VAR_KEY,                     // 19
212 	VM_VAR_COMPUTER,                // 20
213 	VM_VAR_WINDOW_AUTO_CLOSE_TIMER, // 21
214 	VM_VAR_SOUNDGENERATOR,          // 22
215 	VM_VAR_VOLUME,                  // 23
216 	VM_VAR_MAX_INPUT_CHARACTERS,    // 24
217 	VM_VAR_SELECTED_INVENTORY_ITEM, // 25
218 	VM_VAR_MONITOR = 26,            // 26
219 	VM_VAR_MOUSE_BUTTONSTATE = 27,  // 27
220 	VM_VAR_MOUSE_X = 28,            // 28
221 	VM_VAR_MOUSE_Y = 29             // 29
222 };
223 
224 /**
225  * Different monitor types.
226  * Used with AGI variable 26 i.e. vMonitor.
227  */
228 enum AgiMonitorType {
229 	kAgiMonitorCga = 0,
230 	//kAgiMonitorTandy = 1, // Not sure about this
231 	kAgiMonitorHercules = 2,
232 	kAgiMonitorEga = 3
233 	//kAgiMonitorVga = 4 // Not sure about this
234 };
235 
236 /**
237  * Different computer types.
238  * Used with AGI variable 20 i.e. vComputer.
239  *
240  * At least these Amiga AGI versions use value 5:
241  * 2.082 (King's Quest I v1.0U 1986)
242  * 2.090 (King's Quest III v1.01 1986-11-08)
243  * x.yyy (Black Cauldron v2.00 1987-06-14)
244  * x.yyy (Larry I v1.05 1987-06-26)
245  * 2.107 (King's Quest II v2.0J. Date is probably 1987-01-29)
246  * 2.202 (Space Quest II v2.0F)
247  * 2.310 (Police Quest I v2.0B 1989-02-22)
248  * 2.316 (Gold Rush! v2.05 1989-03-09)
249  * 2.333 (King's Quest III v2.15 1989-11-15)
250  *
251  * At least these Amiga AGI versions use value 20:
252  * 2.082 (Space Quest I v1.2 1986)
253  * x.yyy (Manhunter NY 1.06 3/18/89)
254  * 2.333 (Manhunter SF 3.06 8/17/89)
255  *
256  */
257 enum AgiComputerType {
258 	kAgiComputerPC = 0,
259 	kAgiComputerAtariST = 4,
260 	kAgiComputerAmiga = 5, // Newer Amiga AGI interpreters' value (Commonly used)
261 	kAgiComputerApple2GS = 7,
262 	kAgiComputerAmigaOld = 20 // Older Amiga AGI interpreters' value (Seldom used)
263 };
264 
265 enum AgiSoundType {
266 	kAgiSoundPC = 1,
267 	kAgiSoundTandy = 3, // Tandy (This value is also used by the Amiga AGI and Apple IIGS AGI)
268 	kAgiSound2GSOld = 8 // Apple IIGS's Gold Rush! (Version 1.0M 1989-02-28 (CE), AGI 3.003) uses value 8
269 };
270 
271 /**
272  * AGI flags
273  */
274 enum {
275 	VM_FLAG_EGO_WATER = 0,  // 0
276 	VM_FLAG_EGO_INVISIBLE,
277 	VM_FLAG_ENTERED_CLI,
278 	VM_FLAG_EGO_TOUCHED_P2,
279 	VM_FLAG_SAID_ACCEPTED_INPUT,
280 	VM_FLAG_NEW_ROOM_EXEC,  // 5
281 	VM_FLAG_RESTART_GAME,
282 	VM_FLAG_SCRIPT_BLOCKED,
283 	VM_FLAG_JOY_SENSITIVITY,
284 	VM_FLAG_SOUND_ON,
285 	VM_FLAG_DEBUGGER_ON,        // 10
286 	VM_FLAG_LOGIC_ZERO_FIRST_TIME,
287 	VM_FLAG_RESTORE_JUST_RAN,
288 	VM_FLAG_STATUS_SELECTS_ITEMS,
289 	VM_FLAG_MENUS_ACCESSIBLE,
290 	VM_FLAG_OUTPUT_MODE,        // 15
291 	VM_FLAG_AUTO_RESTART
292 };
293 
294 struct AgiControllerKeyMapping {
295 	uint16 keycode;
296 	byte   controllerSlot;
297 
AgiControllerKeyMappingAgiControllerKeyMapping298 	AgiControllerKeyMapping() : keycode(0), controllerSlot(0) {}
299 };
300 
301 struct AgiObject {
302 	int location;
303 	Common::String name;
304 };
305 
306 struct AgiDir {
307 	uint8 volume;
308 	uint32 offset;
309 	uint32 len;
310 	uint32 clen;
311 
312 	// 0 = not in mem, can be freed
313 	// 1 = in mem, can be released
314 	// 2 = not in mem, cant be released
315 	// 3 = in mem, cant be released
316 	// 0x40 = was compressed
317 	uint8 flags;
318 
resetAgiDir319 	void reset() {
320 		volume = 0;
321 		offset = 0;
322 		len = 0;
323 		clen = 0;
324 		flags = 0;
325 	}
326 
AgiDirAgiDir327 	AgiDir() { reset(); }
328 };
329 
330 struct AgiBlock {
331 	bool active;
332 	int16 x1, y1;
333 	int16 x2, y2;
334 
AgiBlockAgiBlock335 	AgiBlock() : active(false), x1(0), y1(0), x2(0), y2(0) {}
336 };
337 
338 struct ScriptPos {
339 	int script;
340 	int curIP;
341 };
342 
343 enum CycleInnerLoopType {
344 	CYCLE_INNERLOOP_GETSTRING = 0,
345 	CYCLE_INNERLOOP_GETNUMBER,
346 	CYCLE_INNERLOOP_INVENTORY,
347 	CYCLE_INNERLOOP_MENU_VIA_KEYBOARD,
348 	CYCLE_INNERLOOP_MENU_VIA_MOUSE,
349 	CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT,
350 	CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION,
351 	CYCLE_INNERLOOP_MESSAGEBOX,
352 	CYCLE_INNERLOOP_HAVEKEY
353 };
354 
355 typedef Common::Array<int16> SavedGameSlotIdArray;
356 
357 /**
358  * AGI game structure.
359  * This structure contains all global data of an AGI game executed
360  * by the interpreter.
361  */
362 struct AgiGame {
363 	AgiEngine *_vm;
364 
365 	// TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames.
366 	//       If they must be then loading and saving is partially broken at the moment.
367 	int adjMouseX;  /**< last given adj.ego.move.to.x.y-command's 1st parameter */
368 	int adjMouseY;  /**< last given adj.ego.move.to.x.y-command's 2nd parameter */
369 
370 	char name[8];   /**< lead in id (e.g. `GR' for goldrush) */
371 	char id[8];     /**< game id */
372 	uint32 crc;     /**< game CRC */
373 
374 	// game flags and variables
375 	uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags combined into a total of 32 bytes */
376 	uint8 vars[MAX_VARS];   /**< 256 variables */
377 
378 	// internal variables
379 	int16 horizon;          /**< horizon y coordinate */
380 
381 	bool  cycleInnerLoopActive;
382 	int16 cycleInnerLoopType;
383 
384 	int16 curLogicNr;               /**< current logic number */
385 	Common::Array<ScriptPos> execStack;
386 
387 	// internal flags
388 	bool playerControl; /**< player is in control */
389 	bool exitAllLogics; /**< break cycle after new.room */
390 	bool pictureShown;  /**< show.pic has been issued */
391 #define ID_AGDS     0x00000001
392 #define ID_AMIGA    0x00000002
393 	int gameFlags;      /**< agi options flags */
394 
395 	// windows
396 	AgiBlock block;
397 
398 	// graphics & text
399 	bool gfxMode;
400 
401 	unsigned int numObjects;
402 
403 	bool controllerOccured[MAX_CONTROLLERS];  /**< keyboard keypress events */
404 	AgiControllerKeyMapping controllerKeyMapping[MAX_CONTROLLER_KEYMAPPINGS];
405 
406 	char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */
407 
408 	// directory entries for resources
409 	AgiDir dirLogic[MAX_DIRECTORY_ENTRIES];
410 	AgiDir dirPic[MAX_DIRECTORY_ENTRIES];
411 	AgiDir dirView[MAX_DIRECTORY_ENTRIES];
412 	AgiDir dirSound[MAX_DIRECTORY_ENTRIES];
413 
414 	// resources
415 	AgiPicture pictures[MAX_DIRECTORY_ENTRIES]; /**< AGI picture resources */
416 	AgiLogic logics[MAX_DIRECTORY_ENTRIES];     /**< AGI logic resources */
417 	AgiView views[MAX_DIRECTORY_ENTRIES];       /**< AGI view resources */
418 	AgiSound *sounds[MAX_DIRECTORY_ENTRIES];    /**< Pointers to AGI sound resources */
419 
420 	AgiLogic *_curLogic;
421 
422 	// view table
423 	ScreenObjEntry screenObjTable[SCREENOBJECTS_MAX];
424 
425 	ScreenObjEntry addToPicView;
426 
427 	bool automaticSave;             /**< set by CmdSetSimple() */
428 	char automaticSaveDescription[SAVEDGAME_DESCRIPTION_LEN + 1];
429 
430 	Common::Rect mouseFence;        /**< rectangle set by fence.mouse command */
431 	bool mouseEnabled;              /**< if mouse is supposed to be active */
432 	bool mouseHidden;               /**< if mouse is currently hidden */
433 
434 	// IF condition handling
435 	int testResult;
436 
437 	int max_logics;
438 	int logic_list[256];
439 
440 	// used to detect situations, where the game shows some text and changes rooms right afterwards
441 	// for example Space Quest 2 intro right at the start
442 	// or Space Quest 2, when entering the vent also right at the start
443 	// The developers assumed that loading the new room would take a bit.
444 	// In ScummVM it's basically done in an instant, which means that
445 	// the text would only get shown for a split second.
446 	// We delay a bit as soon as such situations get detected.
447 	bool nonBlockingTextShown;
448 	int16 nonBlockingTextCyclesLeft;
449 
450 	bool automaticRestoreGame;
451 
452 	uint16 appleIIgsSpeedControllerSlot;
453 	int appleIIgsSpeedLevel;
454 
455 	void setAppleIIgsSpeedLevel(int appleIIgsSpeedLevel);
456 
AgiGameAgiGame457 	AgiGame() {
458 		_vm = nullptr;
459 
460 		adjMouseX = 0;
461 		adjMouseY = 0;
462 
463 		for (uint16 i = 0; i < ARRAYSIZE(name); i++) {
464 			name[i] = 0;
465 		}
466 		for (uint16 i = 0; i < ARRAYSIZE(id); i++) {
467 			id[i] = 0;
468 		}
469 		crc = 0;
470 
471 		for (uint16 i = 0; i < ARRAYSIZE(flags); i++) {
472 			flags[i] = 0;
473 		}
474 		for (uint16 i = 0; i < ARRAYSIZE(vars); i++) {
475 			vars[i] = 0;
476 		}
477 
478 		horizon = 0;
479 
480 		cycleInnerLoopActive = false;
481 		cycleInnerLoopType = 0;
482 
483 		curLogicNr = 0;
484 
485 		// execStack is defaulted by Common::Array constructor
486 
487 		playerControl = false;
488 		exitAllLogics = false;
489 		pictureShown = false;
490 		gameFlags = 0;
491 
492 		// block defaulted by AgiBlock constructor
493 
494 		gfxMode = false;
495 
496 		numObjects = 0;
497 
498 		for (uint16 i = 0; i < ARRAYSIZE(controllerOccured); i++) {
499 			controllerOccured[i] = false;
500 		}
501 
502 		// controllerKeyMapping defaulted by AgiControllerKeyMapping constructor
503 
504 		for (uint16 i = 0; i < MAX_STRINGS + 1; i++) {
505 			for (uint16 j = 0; j < MAX_STRINGLEN; j++) {
506 				strings[i][j] = 0;
507 			}
508 		}
509 
510 		// dirLogic cleared by AgiDir constructor
511 		// dirPic cleared by AgiDir constructor
512 		// dirView cleared by AgiDir constructor
513 		// dirSound cleared by AgiDir constructor
514 
515 		// pictures cleared by AgiPicture constructor
516 		// logics cleared by AgiLogic constructor
517 		// views cleared by AgiView constructor
518 		for (uint16 i = 0; i < ARRAYSIZE(sounds); i++) {
519 			sounds[i] = nullptr;
520 		}
521 
522 		_curLogic = nullptr;
523 
524 		// screenObjTable cleared by ScreenObjEntry constructor
525 
526 		// addToPicView cleared by ScreenObjEntry constructor
527 
528 		automaticSave = false;
529 		for (uint16 i = 0; i < ARRAYSIZE(automaticSaveDescription); i++) {
530 			automaticSaveDescription[i] = 0;
531 		}
532 
533 		// mouseFence cleared by Common::Rect constructor
534 		mouseEnabled = false;
535 		mouseHidden = false;
536 
537 		testResult = 0;
538 
539 		max_logics = 0;
540 		for (uint16 i = 0; i < ARRAYSIZE(logic_list); i++) {
541 			logic_list[i] = 0;
542 		}
543 
544 		nonBlockingTextShown = false;
545 		nonBlockingTextCyclesLeft = 0;
546 
547 		automaticRestoreGame = false;
548 
549 		appleIIgsSpeedControllerSlot = 0xffff;	// we didn't add yet speed menu
550 		appleIIgsSpeedLevel = 2;  // normal speed
551 	}
552 };
553 
554 class AgiLoader {
555 public:
556 
AgiLoader()557 	AgiLoader() {}
~AgiLoader()558 	virtual ~AgiLoader() {}
559 
560 	virtual int init() = 0;
561 	virtual int deinit() = 0;
562 	virtual int detectGame() = 0;
563 	virtual int loadResource(int16 resourceType, int16 resourceNr) = 0;
564 	virtual int unloadResource(int16 resourceType, int16 resourceNr) = 0;
565 	virtual int loadObjects(const char *) = 0;
566 	virtual int loadWords(const char *) = 0;
567 };
568 
569 class AgiLoader_v1 : public AgiLoader {
570 private:
571 	AgiEngine *_vm;
572 	Common::String _filenameDisk0;
573 	Common::String _filenameDisk1;
574 
575 	int loadDir_DDP(AgiDir *agid, int offset, int max);
576 	int loadDir_BC(AgiDir *agid, int offset, int max);
577 	uint8 *loadVolRes(AgiDir *agid);
578 
579 public:
580 	AgiLoader_v1(AgiEngine *vm);
581 
582 	int init() override;
583 	int deinit() override;
584 	int detectGame() override;
585 	int loadResource(int16 resourceType, int16 resourceNr) override;
586 	int unloadResource(int16 resourceType, int16 resourceNr) override;
587 	int loadObjects(const char *) override;
588 	int loadWords(const char *) override;
589 };
590 
591 class AgiLoader_v2 : public AgiLoader {
592 private:
593 	AgiEngine *_vm;
594 
595 	int loadDir(AgiDir *agid, const char *fname);
596 	uint8 *loadVolRes(AgiDir *agid);
597 
598 public:
599 
AgiLoader_v2(AgiEngine * vm)600 	AgiLoader_v2(AgiEngine *vm) {
601 		_vm = vm;
602 	}
603 
604 	int init() override;
605 	int deinit() override;
606 	int detectGame() override;
607 	int loadResource(int16 resourceType, int16 resourceNr) override;
608 	int unloadResource(int16 resourceType, int16 resourceNr) override;
609 	int loadObjects(const char *) override;
610 	int loadWords(const char *) override;
611 };
612 
613 class AgiLoader_v3 : public AgiLoader {
614 private:
615 	AgiEngine *_vm;
616 
617 	int loadDir(AgiDir *agid, Common::File *fp, uint32 offs, uint32 len);
618 	uint8 *loadVolRes(AgiDir *agid);
619 
620 public:
621 
AgiLoader_v3(AgiEngine * vm)622 	AgiLoader_v3(AgiEngine *vm) {
623 		_vm = vm;
624 	}
625 
626 	int init() override;
627 	int deinit() override;
628 	int detectGame() override;
629 	int loadResource(int16 resourceType, int16 resourceNr) override;
630 	int unloadResource(int16 resourceType, int16 resourceNr) override;
631 	int loadObjects(const char *) override;
632 	int loadWords(const char *) override;
633 };
634 
635 class GfxFont;
636 class GfxMgr;
637 class SpritesMgr;
638 class InventoryMgr;
639 class TextMgr;
640 class GfxMenu;
641 class SystemUI;
642 class Words;
643 
644 // Image stack support
645 struct ImageStackElement {
646 	uint8 type;
647 	uint8 pad;
648 	int16 parm1;
649 	int16 parm2;
650 	int16 parm3;
651 	int16 parm4;
652 	int16 parm5;
653 	int16 parm6;
654 	int16 parm7;
655 };
656 
657 struct StringData {
658 	int x;
659 	int y;
660 	int len;
661 	int str;
662 };
663 
664 #define TICK_SECONDS 20
665 
666 #define KEY_QUEUE_SIZE 16
667 
668 class AgiBase : public ::Engine {
669 protected:
670 	// Engine API
671 	Common::Error init();
672 	virtual Common::Error go() = 0;
run()673 	Common::Error run() override {
674 		Common::Error err;
675 		err = init();
676 		if (err.getCode() != Common::kNoError)
677 			return err;
678 		return go();
679 	}
680 	bool hasFeature(EngineFeature f) const override;
681 
682 	virtual void initialize() = 0;
683 
684 	void initRenderMode();
685 
686 public:
687 	Words *_words;
688 
689 	GfxFont *_font;
690 	GfxMgr  *_gfx;
691 
692 	Common::RenderMode _renderMode;
693 	AgiDebug _debug;
694 	AgiGame _game;
695 	Common::RandomSource *_rnd;
696 
697 	SoundMgr *_sound;
698 
699 	Mouse _mouse;
700 
701 	bool _noSaveLoadAllowed;
702 
promptIsEnabled()703 	virtual bool promptIsEnabled() {
704 		return false;
705 	}
706 
707 	virtual int getKeypress() = 0;
708 	virtual bool isKeypress() = 0;
709 	virtual void clearKeyQueue() = 0;
710 
711 	AgiBase(OSystem *syst, const AGIGameDescription *gameDesc);
712 	~AgiBase() override;
713 
714 	virtual void clearImageStack() = 0;
715 	virtual void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
716 	                                  int16 p4, int16 p5, int16 p6, int16 p7) = 0;
717 	virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
718 	                                  int16 p4, int16 p5, int16 p6, int16 p7) = 0;
719 	virtual void releaseImageStack() = 0;
720 
721 	int _soundemu;
722 
723 	bool getFlag(int16 flagNr);
724 	void setFlag(int16 flagNr, bool newState);
725 	void flipFlag(int16 flagNr);
726 
727 	const AGIGameDescription *_gameDescription;
728 
729 	uint32 _gameFeatures;
730 	uint16 _gameVersion;
731 
732 	uint32 getGameID() const;
733 	uint32 getFeatures() const;
734 	uint16 getVersion() const;
735 	uint16 getGameType() const;
736 	Common::Language getLanguage() const;
737 	bool isLanguageRTL() const;
738 	Common::Platform getPlatform() const;
739 	const char *getGameMD5() const;
740 	void initFeatures();
741 	void setFeature(uint32 feature);
742 	void initVersion();
743 	void setVersion(uint16 version);
744 
745 	const char *getDiskName(uint16 id);
746 
747 	bool canLoadGameStateCurrently() override;
748 	bool canSaveGameStateCurrently() override;
749 
750 	const byte *getFontData();
751 
cycleInnerLoopActive(int16 loopType)752 	void cycleInnerLoopActive(int16 loopType) {
753 		_game.cycleInnerLoopActive = true;
754 		_game.cycleInnerLoopType = loopType;
755 	};
cycleInnerLoopInactive()756 	void cycleInnerLoopInactive() {
757 		_game.cycleInnerLoopActive = false;
758 	};
cycleInnerLoopIsActive()759 	bool cycleInnerLoopIsActive() {
760 		return _game.cycleInnerLoopActive;
761 	}
762 };
763 
764 enum AgiArtificialDelayTriggerType {
765 	ARTIFICIALDELAYTYPE_NEWROOM = 0,
766 	ARTIFICIALDELAYTYPE_NEWPICTURE = 1,
767 	ARTIFICIALDELAYTYPE_END = -1
768 };
769 
770 struct AgiArtificialDelayEntry {
771 	uint32 gameId;
772 	Common::Platform platform;
773 	AgiArtificialDelayTriggerType triggerType;
774 	int16 orgNr;
775 	int16 newNr;
776 	uint16 millisecondsDelay;
777 };
778 
779 typedef void (*AgiOpCodeFunction)(AgiGame *state, AgiEngine *vm, uint8 *p);
780 
781 struct AgiOpCodeEntry {
782 	const char *name;
783 	const char *parameters;
784 	AgiOpCodeFunction functionPtr;
785 	uint16     parameterSize;
786 };
787 
788 struct AgiOpCodeDefinitionEntry {
789 	const char *name;
790 	const char *parameters;
791 	AgiOpCodeFunction functionPtr;
792 };
793 
794 class AgiEngine : public AgiBase {
795 protected:
796 	// Engine APIs
797 	Common::Error go() override;
798 
799 	void initialize() override;
800 
801 public:
802 	AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc);
803 	~AgiEngine() override;
804 
805 	bool promptIsEnabled() override;
806 
807 	Common::Error loadGameState(int slot) override;
808 	Common::Error saveGameState(int slot, const Common::String &description, bool isAutosave = false) override;
809 
810 private:
811 	int _keyQueue[KEY_QUEUE_SIZE];
812 	int _keyQueueStart;
813 	int _keyQueueEnd;
814 
815 	bool _allowSynthetic;
816 
817 	bool checkPriority(ScreenObjEntry *v);
818 	bool checkCollision(ScreenObjEntry *v);
819 	bool checkPosition(ScreenObjEntry *v);
820 
821 	int _firstSlot;
822 
823 public:
824 	Common::Array<AgiObject> _objects;    // objects in the game
825 
826 	StringData _stringdata;
827 
828 	SavedGameSlotIdArray getSavegameSlotIds();
829 	bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid);
830 
831 	int saveGame(const Common::String &fileName, const Common::String &descriptionString);
832 	int loadGame(const Common::String &fileName, bool checkId = true);
833 	bool saveGameDialog();
834 	bool saveGameAutomatic();
835 	bool loadGameDialog();
836 	bool loadGameAutomatic();
837 	int doSave(int slot, const Common::String &desc);
838 	int doLoad(int slot, bool showMessages);
839 	int scummVMSaveLoadDialog(bool isSave);
840 
841 	uint8 *_intobj;
842 	bool _restartGame;
843 
844 	SpritesMgr *_sprites;
845 	TextMgr *_text;
846 	InventoryMgr *_inventory;
847 	PictureMgr *_picture;
848 	AgiLoader *_loader; // loader
849 	GfxMenu *_menu;
850 	SystemUI *_systemUI;
851 
852 	Common::Stack<ImageStackElement> _imageStack;
853 
854 	void clearImageStack() override;
855 	void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
856 	                          int16 p4, int16 p5, int16 p6, int16 p7) override;
857 	void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3,
858 	                          int16 p4, int16 p5, int16 p6, int16 p7) override;
859 	void releaseImageStack() override;
860 
861 	void wait(uint32 msec, bool busy = false);
862 
863 	int agiInit();
864 	int agiDeinit();
865 	int agiDetectGame();
866 	int agiLoadResource(int16 resourceType, int16 resourceNr);
867 	int agiUnloadResource(int16 resourceType, int16 resourceNr);
868 	void agiUnloadResources();
869 
870 	int getKeypress() override;
871 	bool isKeypress() override;
872 	void clearKeyQueue() override;
873 
874 	byte getVar(int16 varNr);
875 	void setVar(int16 varNr, byte newValue);
876 
877 private:
878 	void applyVolumeToMixer();
879 
880 public:
881 	void syncSoundSettings() override;
882 
883 public:
884 	void decrypt(uint8 *mem, int len);
885 	void releaseSprites();
886 	uint16 processAGIEvents();
887 	int viewPictures();
888 	int runGame();
889 	int getAppDir(char *appDir, unsigned int size);
890 
891 	int setupV2Game(int ver);
892 	int setupV3Game(int ver);
893 
894 	void newRoom(int16 newRoomNr);
895 	void resetControllers();
896 	void interpretCycle();
897 	int playGame();
898 
899 	void allowSynthetic(bool);
900 	void processScummVMEvents();
901 	void checkQuickLoad();
902 
903 	// Objects
904 public:
905 	int showObjects();
906 	int loadObjects(const char *fname);
907 	int loadObjects(Common::File &fp);
908 	const char *objectName(uint16 objectNr);
909 	int objectGetLocation(uint16 objectNr);
910 	void objectSetLocation(uint16 objectNr, int);
911 private:
912 	int decodeObjects(uint8 *mem, uint32 flen);
913 	int readObjects(Common::File &fp, int flen);
914 
915 	// Logic
916 public:
917 	int decodeLogic(int16 logicNr);
918 	void unloadLogic(int16 logicNr);
919 	int runLogic(int16 logicNr);
920 	void debugConsole(int, int, const char *);
921 	bool testIfCode(int16 logicNr);
922 	void executeAgiCommand(uint8, uint8 *);
923 
924 private:
925 	bool _veryFirstInitialCycle; /**< signals, that currently the very first cycle is executed (restarts, etc. do not count!) */
926 	uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */
927 
928 	bool _setVolumeBrokenFangame;
929 
930 	void resetGetVarSecondsHeuristic();
931 	void getVarSecondsHeuristicTrigger();
932 	uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */
933 	uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */
934 
935 	uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */
936 
937 	void setVarSecondsTrigger(byte newSeconds);
938 
939 public:
940 	// Some submethods of testIfCode
941 	void skipInstruction(byte op);
942 	void skipInstructionsUntil(byte v);
943 	uint8 testObjRight(uint8, uint8, uint8, uint8, uint8);
944 	uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8);
945 	uint8 testObjInBox(uint8, uint8, uint8, uint8, uint8);
946 	uint8 testPosn(uint8, uint8, uint8, uint8, uint8);
947 	uint8 testSaid(uint8, uint8 *);
948 	uint8 testController(uint8);
949 	uint8 testCompareStrings(uint8, uint8);
950 
951 	// View
952 private:
953 
954 	void lSetLoop(ScreenObjEntry *screenObj, int16 loopNr);
955 	void updateView(ScreenObjEntry *screenObj);
956 
957 public:
958 	void setView(ScreenObjEntry *screenObj, int16 viewNr);
959 	void setLoop(ScreenObjEntry *screenObj, int16 loopNr);
960 	void setCel(ScreenObjEntry *screenObj, int16 celNr);
961 
962 	void clipViewCoordinates(ScreenObjEntry *screenObj);
963 
964 	void startUpdate(ScreenObjEntry *);
965 	void stopUpdate(ScreenObjEntry *);
966 	void updateScreenObjTable();
967 	void unloadView(int16 viewNr);
968 	int decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr);
969 
970 private:
971 	void unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
972 	void unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
973 
974 public:
975 	void addToPic(int, int, int, int, int, int, int);
976 	void drawObj(int);
977 	bool isEgoView(const ScreenObjEntry *screenObj);
978 
979 	// Motion
980 private:
981 	int checkStep(int delta, int step);
982 	bool checkBlock(int16 x, int16 y);
983 	void changePos(ScreenObjEntry *screenObj);
984 	void motionWander(ScreenObjEntry *screenObj);
985 	void motionFollowEgo(ScreenObjEntry *screenObj);
986 	void motionMoveObj(ScreenObjEntry *screenObj);
987 	void motionMoveObjStop(ScreenObjEntry *screenObj);
988 	void checkMotion(ScreenObjEntry *screenObj);
989 
990 public:
991 	void motionActivated(ScreenObjEntry *screenObj);
992 	void cyclerActivated(ScreenObjEntry *screenObj);
993 	void checkAllMotions();
994 	void moveObj(ScreenObjEntry *screenObj);
995 	void inDestination(ScreenObjEntry *screenObj);
996 	void fixPosition(int16 screenObjNr);
997 	void fixPosition(ScreenObjEntry *screenObj);
998 	void updatePosition();
999 	int getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize);
1000 
1001 	bool _keyHoldMode;
1002 	Common::KeyCode _keyHoldModeLastKey;
1003 
1004 	// Keyboard
1005 	int doPollKeyboard();
1006 	void cleanKeyboard();
1007 
1008 	bool handleMouseClicks(uint16 &key);
1009 	bool handleController(uint16 key);
1010 
1011 	bool showPredictiveDialog();
1012 
1013 	uint16 agiGetKeypress();
1014 	int waitKey();
1015 	int waitAnyKey();
1016 
1017 	void nonBlockingText_IsShown();
1018 	void nonBlockingText_Forget();
1019 
1020 	void artificialDelay_Reset();
1021 	void artificialDelay_CycleDone();
1022 
1023 	uint16 artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr);
1024 
1025 	void artificialDelayTrigger_NewRoom(int16 newRoomNr);
1026 	void artificialDelayTrigger_DrawPicture(int16 newPictureNr);
1027 
1028 private:
1029 	int16 _artificialDelayCurrentRoom;
1030 	int16 _artificialDelayCurrentPicture;
1031 
1032 public:
1033 	void redrawScreen();
1034 
1035 	void inGameTimerReset(uint32 newPlayTime = 0);
1036 	void inGameTimerResetPassedCycles();
1037 	uint32 inGameTimerGet();
1038 	uint32 inGameTimerGetPassedCycles();
1039 
1040 	void inGameTimerUpdate();
1041 
1042 private:
1043 	uint32 _lastUsedPlayTimeInCycles; // 40 per second
1044 	uint32 _lastUsedPlayTimeInSeconds; // actual seconds
1045 	uint32 _passedPlayTimeCycles; // increased by 1 every time we passed a cycle
1046 
1047 private:
1048 	AgiOpCodeEntry _opCodes[256]; // always keep those at 256, so that there is no way for invalid memory access
1049 	AgiOpCodeEntry _opCodesCond[256];
1050 
1051 	void setupOpCodes(uint16 version);
1052 
1053 public:
getOpCodesTable()1054 	const AgiOpCodeEntry *getOpCodesTable() { return _opCodes; }
1055 };
1056 
1057 } // End of namespace Agi
1058 
1059 #endif /* AGI_AGI_H */
1060