2007-05-30 21:56:52 +00:00
/* ScummVM - Graphic Adventure Engine
2006-05-23 23:43:52 +00:00
*
2007-05-30 21:56:52 +00:00
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
2006-05-23 23:43:52 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2014-02-18 01:34:17 +00:00
*
2006-05-23 23:43:52 +00:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2014-02-18 01:34:17 +00:00
*
2006-05-23 23:43:52 +00:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
2008-01-05 21:10:49 +00:00
# include "common/md5.h"
2006-05-23 23:43:52 +00:00
# include "common/file.h"
2010-11-19 17:03:07 +00:00
# include "common/memstream.h"
2006-05-23 23:43:52 +00:00
# include "common/savefile.h"
# include "common/config-manager.h"
2010-05-04 11:59:22 +00:00
# include "common/debug-channels.h"
2010-03-18 15:07:11 +00:00
# include "common/random.h"
2011-04-24 08:34:27 +00:00
# include "common/textconsole.h"
2006-05-23 23:43:52 +00:00
2010-05-04 11:58:12 +00:00
# include "engines/util.h"
2006-05-23 23:43:52 +00:00
# include "base/plugins.h"
2007-01-12 02:31:04 +00:00
# include "base/version.h"
2006-05-23 23:43:52 +00:00
2006-05-25 22:51:42 +00:00
# include "graphics/cursorman.h"
2011-02-09 01:09:01 +00:00
# include "audio/mididrv.h"
2006-05-23 23:43:52 +00:00
# include "agi/agi.h"
2016-01-29 15:18:31 +00:00
# include "agi/font.h"
2006-05-23 23:43:52 +00:00
# include "agi/graphics.h"
2016-01-29 12:13:40 +00:00
# include "agi/inv.h"
2006-05-23 23:43:52 +00:00
# include "agi/sprite.h"
2016-01-29 12:13:40 +00:00
# include "agi/text.h"
2006-05-23 23:43:52 +00:00
# include "agi/keyboard.h"
# include "agi/menu.h"
2016-01-29 12:13:40 +00:00
# include "agi/systemui.h"
# include "agi/words.h"
2006-05-23 23:43:52 +00:00
2012-02-22 15:15:02 +00:00
# include "gui/predictivedialog.h"
2006-05-23 23:43:52 +00:00
namespace Agi {
2007-03-17 16:08:29 +00:00
void AgiEngine : : allowSynthetic ( bool allow ) {
_allowSynthetic = allow ;
}
2016-02-03 01:40:01 +00:00
void AgiEngine : : wait ( uint32 msec , bool busy ) {
2009-06-06 17:39:42 +00:00
uint32 endTime = _system - > getMillis ( ) + msec ;
2016-02-03 01:40:01 +00:00
if ( busy ) {
_gfx - > setMouseCursor ( true ) ; // Busy mouse cursor
}
2009-06-06 17:41:29 +00:00
2016-02-03 01:40:01 +00:00
do {
2016-02-03 01:21:07 +00:00
processScummVMEvents ( ) ;
2016-02-03 01:40:01 +00:00
_console - > onFrame ( ) ;
2009-06-06 17:39:42 +00:00
_system - > updateScreen ( ) ;
_system - > delayMillis ( 10 ) ;
2016-02-03 01:40:01 +00:00
} while ( _system - > getMillis ( ) < endTime ) ;
if ( busy ) {
_gfx - > setMouseCursor ( ) ; // regular mouse cursor
2009-06-06 17:39:42 +00:00
}
2006-05-23 23:43:52 +00:00
}
2006-12-06 19:27:02 +00:00
int AgiEngine : : agiInit ( ) {
2006-05-23 23:43:52 +00:00
int ec , i ;
debug ( 2 , " initializing " ) ;
2009-06-06 17:45:52 +00:00
debug ( 2 , " game version = 0x%x " , getVersion ( ) ) ;
2006-05-23 23:43:52 +00:00
2009-06-06 17:39:13 +00:00
// initialize with adj.ego.move.to.x.y(0, 0) so to speak
2008-01-21 21:09:42 +00:00
_game . adjMouseX = _game . adjMouseY = 0 ;
2009-06-06 17:39:13 +00:00
// reset all flags to false and all variables to 0
2016-01-31 16:35:13 +00:00
memset ( _game . flags , 0 , sizeof ( _game . flags ) ) ;
memset ( _game . vars , 0 , sizeof ( _game . vars ) ) ;
2006-05-23 23:43:52 +00:00
2009-06-06 17:39:13 +00:00
// clear all resources and events
2016-01-29 12:13:40 +00:00
for ( i = 0 ; i < MAX_DIRECTORY_ENTRIES ; i + + ) {
2007-01-16 12:40:51 +00:00
memset ( & _game . views [ i ] , 0 , sizeof ( struct AgiView ) ) ;
memset ( & _game . pictures [ i ] , 0 , sizeof ( struct AgiPicture ) ) ;
memset ( & _game . logics [ i ] , 0 , sizeof ( struct AgiLogic ) ) ;
2007-08-15 22:00:31 +00:00
memset ( & _game . sounds [ i ] , 0 , sizeof ( class AgiSound * ) ) ; // _game.sounds contains pointers now
2007-01-16 12:40:51 +00:00
memset ( & _game . dirView [ i ] , 0 , sizeof ( struct AgiDir ) ) ;
memset ( & _game . dirPic [ i ] , 0 , sizeof ( struct AgiDir ) ) ;
memset ( & _game . dirLogic [ i ] , 0 , sizeof ( struct AgiDir ) ) ;
memset ( & _game . dirSound [ i ] , 0 , sizeof ( struct AgiDir ) ) ;
2006-05-23 23:43:52 +00:00
}
2009-06-06 17:39:13 +00:00
// clear view table
2016-01-29 12:13:40 +00:00
for ( i = 0 ; i < SCREENOBJECTS_MAX ; i + + )
memset ( & _game . screenObjTable [ i ] , 0 , sizeof ( struct ScreenObjEntry ) ) ;
memset ( & _game . addToPicView , 0 , sizeof ( struct ScreenObjEntry ) ) ;
2006-05-23 23:43:52 +00:00
2016-01-29 12:13:40 +00:00
_words - > clearEgoWords ( ) ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
if ( ! _menu )
2016-01-29 12:13:40 +00:00
_menu = new GfxMenu ( this , _gfx , _picture , _text ) ;
2006-09-07 16:13:41 +00:00
2016-01-29 12:13:40 +00:00
_gfx - > initPriorityTable ( ) ;
2006-05-23 23:43:52 +00:00
2011-09-25 15:39:22 +00:00
// Clear the string buffer on startup, but not when the game restarts, as
// some scripts expect that the game strings remain unaffected after a
// restart. An example is script 98 in SQ2, which is not invoked on restart
// to ask Ego's name again. The name is supposed to be maintained in string 1.
// Fixes bug #3292784.
if ( ! _restartGame ) {
for ( i = 0 ; i < MAX_STRINGS ; i + + )
_game . strings [ i ] [ 0 ] = 0 ;
}
2006-05-23 23:43:52 +00:00
2009-06-06 17:39:13 +00:00
// setup emulation
2006-05-23 23:43:52 +00:00
2009-06-06 17:45:52 +00:00
switch ( getVersion ( ) > > 12 ) {
2006-05-23 23:43:52 +00:00
case 2 :
2011-03-16 19:58:57 +00:00
debug ( " Emulating Sierra AGI v%x.%03x " ,
2016-02-02 17:43:36 +00:00
( int ) ( getVersion ( ) > > 12 ) & 0xF ,
( int ) ( getVersion ( ) ) & 0xFFF ) ;
2006-05-23 23:43:52 +00:00
break ;
case 3 :
2011-03-16 19:58:57 +00:00
debug ( " Emulating Sierra AGI v%x.002.%03x " ,
2016-02-02 17:43:36 +00:00
( int ) ( getVersion ( ) > > 12 ) & 0xF ,
( int ) ( getVersion ( ) ) & 0xFFF ) ;
2006-05-23 23:43:52 +00:00
break ;
}
2007-02-13 15:27:36 +00:00
if ( getPlatform ( ) = = Common : : kPlatformAmiga )
_game . gameFlags | = ID_AMIGA ;
if ( getFeatures ( ) & GF_AGDS )
_game . gameFlags | = ID_AGDS ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
if ( _game . gameFlags & ID_AMIGA )
2010-10-26 22:33:49 +00:00
debug ( 1 , " Amiga padded game detected. " ) ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
if ( _game . gameFlags & ID_AGDS )
2010-10-26 22:33:49 +00:00
debug ( 1 , " AGDS mode enabled. " ) ;
2006-05-23 23:43:52 +00:00
2016-02-02 17:43:36 +00:00
ec = _loader - > init ( ) ; // load vol files, etc
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
if ( ec = = errOK )
ec = _loader - > loadObjects ( OBJECTS ) ;
2006-05-23 23:43:52 +00:00
2009-06-06 17:39:13 +00:00
// note: demogs has no words.tok
2007-01-16 12:40:51 +00:00
if ( ec = = errOK )
ec = _loader - > loadWords ( WORDS ) ;
2006-05-23 23:43:52 +00:00
2009-06-06 17:39:13 +00:00
// Load logic 0 into memory
2007-01-16 12:40:51 +00:00
if ( ec = = errOK )
2016-01-29 12:13:40 +00:00
ec = _loader - > loadResource ( RESOURCETYPE_LOGIC , 0 ) ;
2006-05-23 23:43:52 +00:00
2007-07-16 22:55:44 +00:00
# ifdef __DS__
// Normally, the engine loads the predictive text dictionary when the predictive dialog
// is shown. On the DS version, the word completion feature needs the dictionary too.
2012-03-26 00:07:10 +00:00
// FIXME - loadDict() no long exists in AGI as this has been moved to within the
// GUI Predictive Dialog, but DS Word Completion is probably broken due to this...
2007-07-16 22:55:44 +00:00
# endif
2016-02-04 21:53:15 +00:00
_keyHoldMode = false ;
2009-06-06 17:46:19 +00:00
2009-06-06 17:47:29 +00:00
_game . mouseFence . setWidth ( 0 ) ; // Reset
2016-01-31 21:14:35 +00:00
// Reset in-game timer
inGameTimerReset ( ) ;
// Sync volume settings from ScummVM system settings
setVolumeViaSystemSetting ( ) ;
2006-05-23 23:43:52 +00:00
return ec ;
}
/*
* Public functions
*/
2006-12-06 19:27:02 +00:00
void AgiEngine : : agiUnloadResources ( ) {
2006-05-23 23:43:52 +00:00
int i ;
2009-06-06 17:39:13 +00:00
// Make sure logic 0 is always loaded
2016-01-29 12:13:40 +00:00
for ( i = 1 ; i < MAX_DIRECTORY_ENTRIES ; i + + ) {
_loader - > unloadResource ( RESOURCETYPE_LOGIC , i ) ;
2006-05-23 23:43:52 +00:00
}
2016-01-29 12:13:40 +00:00
for ( i = 0 ; i < MAX_DIRECTORY_ENTRIES ; i + + ) {
_loader - > unloadResource ( RESOURCETYPE_VIEW , i ) ;
_loader - > unloadResource ( RESOURCETYPE_PICTURE , i ) ;
_loader - > unloadResource ( RESOURCETYPE_SOUND , i ) ;
2006-05-23 23:43:52 +00:00
}
}
2006-12-06 19:27:02 +00:00
int AgiEngine : : agiDeinit ( ) {
2006-05-23 23:43:52 +00:00
int ec ;
2016-02-03 02:07:50 +00:00
if ( ! _loader )
return errOK ;
2016-02-02 17:43:36 +00:00
_words - > clearEgoWords ( ) ; // remove all words from memory
agiUnloadResources ( ) ; // unload resources in memory
2016-01-29 12:13:40 +00:00
_loader - > unloadResource ( RESOURCETYPE_LOGIC , 0 ) ;
2007-01-16 12:40:51 +00:00
ec = _loader - > deinit ( ) ;
unloadObjects ( ) ;
2016-01-29 12:13:40 +00:00
_words - > unloadDictionary ( ) ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
clearImageStack ( ) ;
2006-05-23 23:43:52 +00:00
return ec ;
}
2016-01-29 12:13:40 +00:00
int AgiEngine : : agiLoadResource ( int16 resourceType , int16 resourceNr ) {
2006-05-23 23:43:52 +00:00
int i ;
2016-01-29 12:13:40 +00:00
i = _loader - > loadResource ( resourceType , resourceNr ) ;
2007-09-01 14:58:46 +00:00
2008-01-05 21:10:49 +00:00
// WORKAROUND: Patches broken picture 147 in a corrupted Amiga version of Gold Rush! (v2.05 1989-03-09).
// The picture can be seen in room 147 after dropping through the outhouse's hole in room 146.
2016-01-29 12:13:40 +00:00
if ( i = = errOK & & getGameID ( ) = = GID_GOLDRUSH & & resourceType = = RESOURCETYPE_PICTURE & & resourceNr = = 147 & & _game . dirPic [ resourceNr ] . len = = 1982 ) {
uint8 * pic = _game . pictures [ resourceNr ] . rdata ;
Common : : MemoryReadStream picStream ( pic , _game . dirPic [ resourceNr ] . len ) ;
Common : : String md5str = Common : : computeStreamMD5AsString ( picStream , _game . dirPic [ resourceNr ] . len ) ;
2010-11-07 17:16:59 +00:00
if ( md5str = = " 1c685eb048656cedcee4eb6eca2cecea " ) {
2008-01-05 21:10:49 +00:00
pic [ 0x042 ] = 0x4B ; // 0x49 -> 0x4B
pic [ 0x043 ] = 0x66 ; // 0x26 -> 0x66
pic [ 0x204 ] = 0x68 ; // 0x28 -> 0x68
pic [ 0x6C0 ] = 0x2D ; // 0x25 -> 0x2D
pic [ 0x6F0 ] = 0xF0 ; // 0x70 -> 0xF0
pic [ 0x734 ] = 0x6F ; // 0x2F -> 0x6F
}
}
2006-05-23 23:43:52 +00:00
return i ;
}
2016-01-29 12:13:40 +00:00
int AgiEngine : : agiUnloadResource ( int16 resourceType , int16 resourceNr ) {
return _loader - > unloadResource ( resourceType , resourceNr ) ;
2006-05-23 23:43:52 +00:00
}
struct GameSettings {
const char * gameid ;
const char * description ;
byte id ;
uint32 features ;
const char * detectname ;
} ;
2007-11-03 21:06:58 +00:00
AgiBase : : AgiBase ( OSystem * syst , const AGIGameDescription * gameDesc ) : Engine ( syst ) , _gameDescription ( gameDesc ) {
2009-06-06 17:42:37 +00:00
_noSaveLoadAllowed = false ;
2009-06-06 17:44:46 +00:00
2011-05-17 10:01:34 +00:00
_rnd = new Common : : RandomSource ( " agi " ) ;
2011-08-14 17:08:44 +00:00
_sound = 0 ;
2011-05-17 10:01:34 +00:00
2009-06-06 17:44:46 +00:00
initFeatures ( ) ;
2009-06-06 17:45:52 +00:00
initVersion ( ) ;
2007-09-01 14:58:46 +00:00
}
2011-05-17 10:01:34 +00:00
AgiBase : : ~ AgiBase ( ) {
delete _rnd ;
2011-08-14 17:08:44 +00:00
2013-04-21 11:12:13 +00:00
delete _sound ;
2011-05-17 10:01:34 +00:00
}
2011-09-26 02:23:42 +00:00
void AgiBase : : initRenderMode ( ) {
2016-01-29 12:13:40 +00:00
Common : : Platform platform = Common : : parsePlatform ( ConfMan . get ( " platform " ) ) ;
Common : : RenderMode configRenderMode = Common : : parseRenderMode ( ConfMan . get ( " render_mode " ) . c_str ( ) ) ;
// Default to EGA PC rendering
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderEGA ;
2016-01-29 12:13:40 +00:00
switch ( platform ) {
case Common : : kPlatformDOS :
2016-02-28 10:23:31 +00:00
// Keep EGA
2016-01-29 12:13:40 +00:00
break ;
case Common : : kPlatformAmiga :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderAmiga ;
2016-01-29 12:13:40 +00:00
break ;
case Common : : kPlatformApple2GS :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderApple2GS ;
2016-01-29 12:13:40 +00:00
break ;
case Common : : kPlatformAtariST :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderAtariST ;
2016-01-29 12:13:40 +00:00
break ;
2016-02-05 15:41:02 +00:00
case Common : : kPlatformMacintosh :
_renderMode = Common : : kRenderMacintosh ;
break ;
2016-01-29 12:13:40 +00:00
default :
break ;
}
2011-09-26 02:23:42 +00:00
2016-01-29 12:13:40 +00:00
// If render mode is explicitly set, force rendermode
switch ( configRenderMode ) {
2016-02-05 21:09:11 +00:00
case Common : : kRenderCGA :
_renderMode = Common : : kRenderCGA ;
break ;
case Common : : kRenderEGA :
_renderMode = Common : : kRenderEGA ;
break ;
case Common : : kRenderVGA :
_renderMode = Common : : kRenderVGA ;
break ;
2016-02-28 10:23:31 +00:00
case Common : : kRenderHercG :
_renderMode = Common : : kRenderHercG ;
break ;
case Common : : kRenderHercA :
_renderMode = Common : : kRenderHercA ;
break ;
2016-01-29 12:13:40 +00:00
case Common : : kRenderAmiga :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderAmiga ;
2016-01-29 12:13:40 +00:00
break ;
case Common : : kRenderApple2GS :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderApple2GS ;
2016-01-29 12:13:40 +00:00
break ;
case Common : : kRenderAtariST :
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderAtariST ;
2016-01-29 12:13:40 +00:00
break ;
2016-02-05 15:41:02 +00:00
case Common : : kRenderMacintosh :
_renderMode = Common : : kRenderMacintosh ;
break ;
2016-01-29 12:13:40 +00:00
default :
break ;
2011-09-26 02:23:42 +00:00
}
2016-01-29 12:13:40 +00:00
if ( getFeatures ( ) & ( GF_AGI256 | GF_AGI256_2 ) ) {
// If current game is AGI256, switch (force) to VGA render mode
2016-01-29 14:43:45 +00:00
_renderMode = Common : : kRenderVGA ;
2011-09-26 02:23:42 +00:00
}
}
2016-01-29 15:18:31 +00:00
const byte * AgiBase : : getFontData ( ) {
return _font - > getFontData ( ) ;
2016-01-29 12:13:40 +00:00
}
2007-11-03 21:06:58 +00:00
AgiEngine : : AgiEngine ( OSystem * syst , const AGIGameDescription * gameDesc ) : AgiBase ( syst , gameDesc ) {
2006-05-23 23:43:52 +00:00
// Setup mixer
2010-08-25 07:41:14 +00:00
syncSoundSettings ( ) ;
2006-05-23 23:43:52 +00:00
2010-04-27 21:40:52 +00:00
DebugMan . addDebugChannel ( kDebugLevelMain , " Main " , " Generic debug level " ) ;
DebugMan . addDebugChannel ( kDebugLevelResources , " Resources " , " Resources debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelSprites , " Sprites " , " Sprites debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelInventory , " Inventory " , " Inventory debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelInput , " Input " , " Input events debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelMenu , " Menu " , " Menu debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelScripts , " Scripts " , " Scripts debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelSound , " Sound " , " Sound debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelText , " Text " , " Text output debugging " ) ;
DebugMan . addDebugChannel ( kDebugLevelSavegame , " Savegame " , " Saving & restoring game debugging " ) ;
2006-05-24 13:08:09 +00:00
2006-12-06 19:27:02 +00:00
2007-01-16 12:40:51 +00:00
memset ( & _game , 0 , sizeof ( struct AgiGame ) ) ;
memset ( & _debug , 0 , sizeof ( struct AgiDebug ) ) ;
2009-10-20 11:13:00 +00:00
memset ( & _mouse , 0 , sizeof ( struct Mouse ) ) ;
2006-12-06 19:27:02 +00:00
2015-05-15 02:09:55 +00:00
_game . mouseEnabled = true ;
2016-01-29 12:13:40 +00:00
_game . mouseHidden = false ;
// don't check for Amiga, Amiga doesn't allow disabling mouse support. It's mandatory.
2015-05-15 03:10:08 +00:00
if ( ! ConfMan . getBool ( " mousesupport " ) ) {
// we effectively disable the mouse for games, that explicitly do not want mouse support to be enabled
2015-05-15 02:09:55 +00:00
_game . mouseEnabled = false ;
2016-01-29 12:13:40 +00:00
_game . mouseHidden = true ;
2015-05-15 02:09:55 +00:00
}
2011-06-13 19:15:13 +00:00
_game . _vm = this ;
2016-01-29 12:13:40 +00:00
_game . gfxMode = true ;
2007-01-16 12:40:51 +00:00
_keyQueueStart = 0 ;
_keyQueueEnd = 0 ;
2006-12-06 19:27:02 +00:00
2007-03-17 16:08:29 +00:00
_allowSynthetic = false ;
2007-01-16 12:40:51 +00:00
_intobj = NULL ;
2006-12-06 19:27:02 +00:00
2007-01-16 12:40:51 +00:00
memset ( & _stringdata , 0 , sizeof ( struct StringData ) ) ;
2006-12-06 19:27:02 +00:00
2007-01-16 12:40:51 +00:00
_objects = NULL ;
2006-12-06 19:27:02 +00:00
2009-06-06 17:40:56 +00:00
_restartGame = false ;
2007-03-12 08:43:13 +00:00
_firstSlot = 0 ;
2009-07-22 11:48:51 +00:00
2011-09-25 21:56:10 +00:00
resetControllers ( ) ;
2010-06-21 21:32:56 +00:00
setupOpcodes ( ) ;
2011-06-13 19:15:13 +00:00
_game . _curLogic = NULL ;
2016-02-20 13:53:17 +00:00
_veryFirstInitialCycle = true ;
2016-02-14 21:43:52 +00:00
_instructionCounter = 0 ;
resetGetVarSecondsHeuristic ( ) ;
2013-05-02 11:17:46 +00:00
2016-02-20 13:53:17 +00:00
_setVolumeBrokenFangame = false ; // for further study see AgiEngine::setVolumeViaScripts()
2013-05-02 11:17:46 +00:00
_lastSaveTime = 0 ;
2016-05-07 08:25:09 +00:00
_playTimeInSecondsAdjust = 0 ;
_lastUsedPlayTimeInCycles = 0 ;
_lastUsedPlayTimeInSeconds = 0 ;
_passedPlayTimeCycles = 0 ;
2013-05-02 11:17:46 +00:00
memset ( _keyQueue , 0 , sizeof ( _keyQueue ) ) ;
2016-02-03 02:07:50 +00:00
_console = nullptr ;
_font = nullptr ;
_gfx = nullptr ;
_sound = nullptr ;
_picture = nullptr ;
_sprites = nullptr ;
_text = nullptr ;
_loader = nullptr ;
_menu = nullptr ;
_systemUI = nullptr ;
_inventory = nullptr ;
2013-05-02 11:17:46 +00:00
2016-02-04 21:53:15 +00:00
_keyHoldMode = false ;
2016-05-07 08:25:09 +00:00
_artificialDelayCurrentRoom = 0 ;
_artificialDelayCurrentPicture = 0 ;
2006-05-23 23:43:52 +00:00
}
void AgiEngine : : initialize ( ) {
2006-06-06 15:38:34 +00:00
// TODO: Some sound emulation modes do not fit our current music
// drivers, and I'm not sure what they are. For now, they might
// as well be called "PC Speaker" and "Not PC Speaker".
2007-08-17 13:10:57 +00:00
// If used platform is Apple IIGS then we must use Apple IIGS sound emulation
// because Apple IIGS AGI games use only Apple IIGS specific sound resources.
2008-04-22 20:33:46 +00:00
if ( getPlatform ( ) = = Common : : kPlatformApple2GS ) {
2007-08-17 13:10:57 +00:00
_soundemu = SOUND_EMU_APPLE2GS ;
2009-06-16 21:59:20 +00:00
} else if ( getPlatform ( ) = = Common : : kPlatformCoCo3 ) {
2009-06-17 23:16:21 +00:00
_soundemu = SOUND_EMU_COCO3 ;
2010-09-21 06:05:27 +00:00
} else if ( ConfMan . get ( " music_driver " ) = = " auto " ) {
// Default sound is the proper PCJr emulation
_soundemu = SOUND_EMU_PCJR ;
2007-08-17 13:10:57 +00:00
} else {
2016-02-02 17:43:36 +00:00
switch ( MidiDriver : : getMusicType ( MidiDriver : : detectDevice ( MDT_PCSPK | MDT_AMIGA | MDT_ADLIB | MDT_PCJR | MDT_MIDI ) ) ) {
2010-06-21 21:36:36 +00:00
case MT_PCSPK :
2007-08-17 13:10:57 +00:00
_soundemu = SOUND_EMU_PC ;
break ;
2010-09-21 05:36:51 +00:00
case MT_ADLIB :
2010-09-21 06:05:27 +00:00
_soundemu = SOUND_EMU_NONE ;
2010-06-15 10:36:10 +00:00
break ;
2010-09-21 05:36:51 +00:00
case MT_PCJR :
2010-09-21 06:05:27 +00:00
_soundemu = SOUND_EMU_PCJR ;
2010-09-21 05:36:51 +00:00
break ;
2010-09-20 21:17:49 +00:00
case MT_AMIGA :
_soundemu = SOUND_EMU_AMIGA ;
2010-06-15 10:34:45 +00:00
break ;
2007-08-17 13:10:57 +00:00
default :
2010-09-21 05:36:51 +00:00
debug ( 0 , " DEF " ) ;
2010-06-15 10:36:10 +00:00
_soundemu = SOUND_EMU_MIDI ;
2007-08-17 13:10:57 +00:00
break ;
}
2006-06-06 15:38:34 +00:00
}
2006-05-23 23:43:52 +00:00
2011-09-26 02:23:42 +00:00
initRenderMode ( ) ;
2006-05-25 19:46:28 +00:00
2006-05-24 21:56:14 +00:00
_console = new Console ( this ) ;
2016-01-29 12:13:40 +00:00
_words = new Words ( this ) ;
2016-01-29 15:18:31 +00:00
_font = new GfxFont ( this ) ;
2016-02-27 20:44:21 +00:00
_gfx = new GfxMgr ( this , _font ) ;
2006-12-06 19:27:02 +00:00
_sound = new SoundMgr ( this , _mixer ) ;
_picture = new PictureMgr ( this , _gfx ) ;
_sprites = new SpritesMgr ( this , _gfx ) ;
2016-01-29 12:13:40 +00:00
_text = new TextMgr ( this , _words , _gfx ) ;
_systemUI = new SystemUI ( this , _gfx , _text ) ;
_inventory = new InventoryMgr ( this , _gfx , _text , _systemUI ) ;
2016-02-27 20:44:21 +00:00
_font - > init ( ) ;
2016-02-10 17:48:53 +00:00
_gfx - > initVideo ( ) ;
2016-01-29 12:13:40 +00:00
_text - > init ( _systemUI ) ;
2006-12-06 19:27:02 +00:00
2007-01-16 12:40:51 +00:00
_game . gameFlags = 0 ;
2006-05-23 23:43:52 +00:00
2016-01-29 12:13:40 +00:00
_text - > charAttrib_Set ( 15 , 0 ) ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
_game . name [ 0 ] = ' \0 ' ;
2006-05-23 23:43:52 +00:00
2008-08-10 22:53:43 +00:00
_lastSaveTime = 0 ;
2006-05-23 23:43:52 +00:00
debugC ( 2 , kDebugLevelMain , " Detect game " ) ;
2006-12-19 01:11:41 +00:00
2007-01-16 12:40:51 +00:00
if ( agiDetectGame ( ) = = errOK ) {
2006-05-23 23:43:52 +00:00
debugC ( 2 , kDebugLevelMain , " game loaded " ) ;
} else {
2010-10-26 22:33:49 +00:00
warning ( " Could not open AGI game " ) ;
2006-05-23 23:43:52 +00:00
}
debugC ( 2 , kDebugLevelMain , " Init sound " ) ;
}
2016-01-29 12:13:40 +00:00
bool AgiEngine : : promptIsEnabled ( ) {
return _text - > promptIsEnabled ( ) ;
}
void AgiEngine : : redrawScreen ( ) {
_game . gfxMode = true ; // enable graphics mode
_gfx - > setPalette ( true ) ; // set graphics mode palette
_text - > charAttrib_Set ( _text - > _textAttrib . foreground , _text - > _textAttrib . background ) ;
_gfx - > clearDisplay ( 0 ) ;
_picture - > showPic ( ) ;
_text - > statusDraw ( ) ;
_text - > promptRedraw ( ) ;
}
2006-05-23 23:43:52 +00:00
AgiEngine : : ~ AgiEngine ( ) {
2006-12-06 19:27:02 +00:00
agiDeinit ( ) ;
2008-05-24 00:08:13 +00:00
delete _loader ;
2016-02-03 02:07:50 +00:00
if ( _gfx ) {
_gfx - > deinitVideo ( ) ;
}
2016-01-29 12:13:40 +00:00
delete _inventory ;
delete _systemUI ;
2016-02-03 02:07:50 +00:00
delete _menu ;
2016-01-29 12:13:40 +00:00
delete _text ;
2006-05-30 18:53:01 +00:00
delete _sprites ;
2008-05-24 00:08:13 +00:00
delete _picture ;
delete _gfx ;
2016-01-29 15:18:31 +00:00
delete _font ;
2016-01-29 12:13:40 +00:00
delete _words ;
2006-05-24 21:40:24 +00:00
delete _console ;
2006-05-23 23:43:52 +00:00
}
2008-11-06 17:05:54 +00:00
Common : : Error AgiBase : : init ( ) {
2006-05-23 23:43:52 +00:00
initialize ( ) ;
2016-01-29 12:13:40 +00:00
_gfx - > setPalette ( true ) ;
2006-05-23 23:43:52 +00:00
2008-11-06 17:05:54 +00:00
return Common : : kNoError ;
2006-05-23 23:43:52 +00:00
}
2008-11-06 17:05:54 +00:00
Common : : Error AgiEngine : : go ( ) {
2015-05-15 02:09:55 +00:00
if ( _game . mouseEnabled ) {
CursorMan . showMouse ( true ) ;
}
2016-01-31 19:53:36 +00:00
inGameTimerReset ( ) ;
2006-05-23 23:43:52 +00:00
2007-01-16 12:40:51 +00:00
runGame ( ) ;
2006-05-23 23:43:52 +00:00
2008-11-06 17:05:54 +00:00
return Common : : kNoError ;
2006-05-23 23:43:52 +00:00
}
2016-01-31 21:25:35 +00:00
void AgiEngine : : syncSoundSettings ( ) {
Engine : : syncSoundSettings ( ) ;
setVolumeViaSystemSetting ( ) ;
}
2016-02-11 16:26:25 +00:00
// WORKAROUND:
// Sometimes Sierra printed some text on the screen and did a room change immediately afterwards expecting the
// interpreter to load the data for a bit of time. This of course doesn't happen in our AGI, so we try to
// detect such situations via heuristic and then delay the game for a bit.
// In those cases a wait mouse cursor will be shown.
//
2016-01-29 12:13:40 +00:00
// Scenes that need this:
//
2016-02-19 11:52:19 +00:00
// Gold Rush:
2016-02-19 15:24:58 +00:00
// - During Stagecoach path, after getting solving the steep hill "Congratulations!!!" (NewRoom)
2016-02-19 11:52:19 +00:00
// - when following your mule "Yet right on his tail!!!" (NewRoom/NewPicture - but room 123 stays the same)
2016-01-29 12:13:40 +00:00
// Manhunter 1:
// - intro text screen (DrawPic)
// - MAD "zooming in..." during intro and other scenes, for example room 124 (NewRoom)
// The NewRoom call is not done during the same cycle as the "zooming in..." print call.
// Space Quest 1:
// - right at the start of the game (NewRoom)
2016-02-13 14:48:55 +00:00
// - right at the end of the asteroids "That was mighty close!" (NewRoom)
2016-01-29 12:13:40 +00:00
// Space Quest 2
// - right at the start of the game (NewRoom)
// - after exiting the very first room, a message pops up, that isn't readable without it (NewRoom)
2016-02-16 18:27:37 +00:00
// - Climbing into shuttle on planet Labion. "You open the hatch and head on in." (NewRoom)
2016-01-29 12:13:40 +00:00
// Games, that must not be triggered:
//
// Fanmade Voodoo Girl:
// - waterfall (DrawPic, room 17)
// - inside shop (NewRoom, changes to same room every new button, room 4)
void AgiEngine : : nonBlockingText_IsShown ( ) {
_game . nonBlockingTextShown = true ;
_game . nonBlockingTextCyclesLeft = 2 ; // 1 additional script cycle is counted too
}
void AgiEngine : : nonBlockingText_Forget ( ) {
_game . nonBlockingTextShown = false ;
_game . nonBlockingTextCyclesLeft = 0 ;
}
2016-02-11 16:26:25 +00:00
void AgiEngine : : artificialDelay_Reset ( ) {
nonBlockingText_Forget ( ) ;
_artificialDelayCurrentRoom = - 1 ;
_artificialDelayCurrentPicture = - 1 ;
}
void AgiEngine : : artificialDelay_CycleDone ( ) {
2016-01-29 12:13:40 +00:00
if ( _game . nonBlockingTextCyclesLeft ) {
_game . nonBlockingTextCyclesLeft - - ;
if ( ! _game . nonBlockingTextCyclesLeft ) {
// cycle count expired, we assume that non-blocking text won't be a problem for room / pic change
_game . nonBlockingTextShown = false ;
}
}
}
2009-06-06 17:44:46 +00:00
2016-02-11 16:26:25 +00:00
// WORKAROUND:
// On Apple IIgs, there are situations like for example the Police Quest 1 intro, where music is playing
// and then the scripts switch to a new room, expecting it to load for a bit of time. In ScummVM this results
// in music getting cut off, because our loading is basically done in an instant. This also happens in the
// original interpreter, when you use a faster CPU in emulation.
//
// That's why there is an additional table, where one can add such situations to it.
// These issues are basically impossible to detect, because sometimes music is also supposed to play throughout
// multiple rooms.
//
// Normally all text-based issues should get detected by the current heuristic. Do not add those in here.
2009-06-06 17:44:46 +00:00
2016-02-11 16:26:25 +00:00
// script, description, signature patch
static const AgiArtificialDelayEntry artificialDelayTable [ ] = {
2016-02-19 14:28:34 +00:00
{ GID_GOLDRUSH , Common : : kPlatformApple2GS , ARTIFICIALDELAYTYPE_NEWROOM , 14 , 21 , 2200 } , // Stagecoach path: right after getting on it in Brooklyn
2016-02-11 16:26:25 +00:00
{ GID_PQ1 , Common : : kPlatformApple2GS , ARTIFICIALDELAYTYPE_NEWPICTURE , 1 , 2 , 2200 } , // Intro: music track is supposed to finish before credits screen. Developers must have assumed that room loading would take that long.
2016-02-18 15:55:49 +00:00
{ GID_MH1 , Common : : kPlatformApple2GS , ARTIFICIALDELAYTYPE_NEWPICTURE , 155 , 183 , 2200 } , // Happens, when hitting fingers at bar
2016-02-11 16:26:25 +00:00
{ GID_AGIDEMO , Common : : kPlatformUnknown , ARTIFICIALDELAYTYPE_END , - 1 , - 1 , 0 }
} ;
2016-01-29 12:13:40 +00:00
2016-02-11 16:26:25 +00:00
uint16 AgiEngine : : artificialDelay_SearchTable ( AgiArtificialDelayTriggerType triggerType , int16 orgNr , int16 newNr ) {
if ( getPlatform ( ) ! = Common : : kPlatformApple2GS ) {
return 0 ;
}
const AgiArtificialDelayEntry * delayEntry = artificialDelayTable ;
while ( delayEntry - > triggerType ! = ARTIFICIALDELAYTYPE_END ) {
if ( triggerType = = delayEntry - > triggerType ) {
if ( ( orgNr = = delayEntry - > orgNr ) & & ( newNr = = delayEntry - > newNr ) ) {
if ( ( getGameID ( ) = = delayEntry - > gameId ) & & ( getPlatform ( ) = = delayEntry - > platform ) ) {
warning ( " artificial delay forced " ) ;
return delayEntry - > millisecondsDelay ;
}
}
}
delayEntry + + ;
}
return 0 ;
}
void AgiEngine : : artificialDelayTrigger_NewRoom ( int16 newRoomNr ) {
uint16 millisecondsDelay = 0 ;
//warning("artificial delay trigger: room %d -> new room %d", _artificialDelayCurrentRoom, newRoomNr);
if ( ! _game . automaticRestoreGame ) {
millisecondsDelay = artificialDelay_SearchTable ( ARTIFICIALDELAYTYPE_NEWROOM , _artificialDelayCurrentRoom , newRoomNr ) ;
if ( _game . nonBlockingTextShown ) {
if ( newRoomNr ! = _artificialDelayCurrentRoom ) {
if ( millisecondsDelay < 2000 ) {
// wait a bit, we detected non-blocking text
millisecondsDelay = 2000 ; // 2 seconds
}
2009-06-06 17:44:46 +00:00
}
}
2016-02-11 16:26:25 +00:00
if ( millisecondsDelay ) {
wait ( millisecondsDelay , true ) ; // set busy mouse cursor
2016-02-19 11:52:19 +00:00
_game . nonBlockingTextShown = false ;
2016-02-11 16:26:25 +00:00
}
2009-06-06 17:44:46 +00:00
}
2016-02-11 16:26:25 +00:00
_artificialDelayCurrentRoom = newRoomNr ;
2016-01-29 12:13:40 +00:00
}
2016-02-11 16:26:25 +00:00
void AgiEngine : : artificialDelayTrigger_DrawPicture ( int16 newPictureNr ) {
uint16 millisecondsDelay = 0 ;
//warning("artificial delay trigger: picture %d -> new picture %d", _artificialDelayCurrentPicture, newPictureNr);
if ( ! _game . automaticRestoreGame ) {
millisecondsDelay = artificialDelay_SearchTable ( ARTIFICIALDELAYTYPE_NEWPICTURE , _artificialDelayCurrentPicture , newPictureNr ) ;
if ( _game . nonBlockingTextShown ) {
2016-02-19 11:52:19 +00:00
if ( newPictureNr ! = _artificialDelayCurrentPicture ) {
if ( millisecondsDelay < 2000 ) {
// wait a bit, we detected non-blocking text
millisecondsDelay = 2000 ; // 2 seconds, set busy
}
2016-02-11 16:26:25 +00:00
}
}
2010-10-26 22:35:37 +00:00
2016-02-11 16:26:25 +00:00
if ( millisecondsDelay ) {
wait ( millisecondsDelay , true ) ; // set busy mouse cursor
2016-02-19 11:52:19 +00:00
_game . nonBlockingTextShown = false ;
2016-01-29 12:13:40 +00:00
}
}
2016-02-11 16:26:25 +00:00
_artificialDelayCurrentPicture = newPictureNr ;
2009-06-06 17:44:46 +00:00
}
2007-01-07 18:02:54 +00:00
} // End of namespace Agi