2008-11-14 21:32:20 +00:00
/* ScummVM - Graphic Adventure Engine
*
* 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 .
*
2021-12-26 18:47:58 +01: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 3 of the License , or
* ( at your option ) any later version .
2014-02-18 02:34:20 +01:00
*
2008-11-14 21:32:20 +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 02:34:20 +01:00
*
2008-11-14 21:32:20 +00:00
* You should have received a copy of the GNU General Public License
2021-12-26 18:47:58 +01:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-11-14 21:32:20 +00:00
*
*/
2021-09-11 02:29:35 -05:00
# include <limits.h>
2011-08-05 13:33:42 +01:00
# include "audio/mididrv.h"
2008-11-14 21:32:20 +00:00
# include "groovie/script.h"
2010-06-07 17:14:42 +00:00
# include "groovie/cursor.h"
# include "groovie/graphics.h"
# include "groovie/music.h"
2021-09-16 09:23:34 +03:00
# include "groovie/video/player.h"
2010-06-07 17:14:42 +00:00
# include "groovie/resource.h"
2009-01-13 23:22:47 +00:00
# include "groovie/saveload.h"
2021-09-16 09:23:34 +03:00
# include "groovie/logic/cell.h"
2021-10-22 01:12:39 +03:00
# include "groovie/logic/tlcgame.h"
2008-11-14 21:32:20 +00:00
2021-09-15 19:28:59 +03:00
# include "gui/saveload.h"
2010-05-11 15:41:31 +00:00
# include "common/archive.h"
2008-11-14 21:32:20 +00:00
# include "common/config-manager.h"
2010-05-04 11:59:22 +00:00
# include "common/debug-channels.h"
2011-05-16 16:35:10 +02:00
# include "common/events.h"
2011-04-24 11:34:27 +03:00
# include "common/file.h"
2010-05-11 15:41:31 +00:00
# include "common/macresman.h"
2011-06-13 22:19:18 +01:00
# include "common/translation.h"
2008-11-14 21:32:20 +00:00
2011-04-25 07:04:40 +01:00
# include "gui/message.h"
2021-09-15 22:50:44 -05:00
const uint NUM_OPCODES = 91 ;
2008-11-14 21:32:20 +00:00
namespace Groovie {
2020-07-02 15:24:03 +02:00
// Adapted from SCRIPT.GRV
const byte t7gMidiInitScript [ ] = {
0x1A , 0x00 , 0x01 , 0xB1 , 0x12 , 0x00 , // strcmpnejmp (if (var 0100 != 01) jmp 0012)
0x02 , 0x46 , 0x4C , // playsong 4C46 (GM init)
0x03 , // bf9on (fade-in)
0x09 , 0x60 , 0x24 , // videofromref 2460 (GM init video)
0x09 , 0x60 , 0x24 , // videofromref 2460 (GM init video)
0x04 , // palfadeout
0x29 , // stopmidi
0x1A , 0x00 , 0x01 , 0xB2 , 0x21 , 0x00 , // :0012 - strcmpnejmp (if (var 0100 != 02) jmp 0021)
0x02 , 0x45 , 0x4C , // playsong 4C45 (MT-32 init)
0x03 , // bf9on (fade-in)
0x09 , 0x61 , 0x24 , // videofromref 2461 (MT-32 init video)
0x04 , // palfadeout
0x29 , // stopmidi
0x31 , 0x63 , 0x00 , 0x00 , 0x00 , // :0021 - midivolume 0063, 0000
0x3C , // checkvalidsaves
0x43 , 0x00 // returnscript 00
} ;
2021-11-14 01:48:18 +02:00
enum kSpecialVariableTypes {
kVarTypeArray = 0x23 ,
kVarType2DArray = 0x7C
} ;
2009-03-10 00:19:44 +00:00
Script : : Script ( GroovieEngine * vm , EngineVersion version ) :
2021-11-13 23:40:27 +02:00
_code ( nullptr ) , _savedCode ( nullptr ) , _stacktop ( 0 ) , _debugger ( nullptr ) , _vm ( vm ) ,
_videoFile ( nullptr ) , _videoRef ( UINT_MAX ) , _cellGame ( nullptr ) , _lastCursor ( 0xff ) ,
2021-12-04 16:23:57 +01:00
# ifdef ENABLE_GROOVIE2
2021-12-04 08:04:35 -06:00
_beehive ( ConfMan . getBool ( " easier_ai " ) ) , _cake ( ConfMan . getBool ( " easier_ai " ) ) , _gallery ( ConfMan . getBool ( " easier_ai " ) ) ,
2021-12-04 16:23:57 +01:00
_mouseTrap ( ConfMan . getBool ( " easier_ai " ) ) , _othello ( ConfMan . getBool ( " easier_ai " ) ) , _pente ( ConfMan . getBool ( " easier_ai " ) ) ,
# endif
_version ( version ) , _random ( " GroovieScripts " ) , _tlcGame ( nullptr )
2021-12-04 08:04:35 -06:00
{
2011-05-11 00:30:02 -04:00
2009-03-10 00:19:44 +00:00
// Initialize the opcode set depending on the engine version
2018-01-07 19:39:25 +01:00
if ( version = = kGroovieT7G ) {
2009-03-10 00:19:44 +00:00
_opcodes = _opcodesT7G ;
2018-01-07 19:39:25 +01:00
} else {
2009-03-10 00:19:44 +00:00
_opcodes = _opcodesV2 ;
}
2008-11-14 21:32:20 +00:00
// Prepare the variables
_bitflags = 0 ;
for ( int i = 0 ; i < 0x400 ; i + + ) {
2008-11-16 19:20:30 +00:00
setVariable ( i , 0 ) ;
2008-11-14 21:32:20 +00:00
}
// Initialize the music type variable
2010-06-25 20:51:57 +00:00
MidiDriver : : DeviceHandle dev = MidiDriver : : detectDevice ( MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM ) ;
2010-06-21 21:36:36 +00:00
if ( MidiDriver : : getMusicType ( dev ) = = MT_ADLIB ) {
2008-11-14 21:32:20 +00:00
// MIDI through AdLib
2008-11-16 19:20:30 +00:00
setVariable ( 0x100 , 0 ) ;
2010-06-21 21:36:36 +00:00
} else if ( ( MidiDriver : : getMusicType ( dev ) = = MT_MT32 ) | | ConfMan . getBool ( " native_mt32 " ) ) {
2008-11-14 21:32:20 +00:00
// MT-32
2008-11-16 19:20:30 +00:00
setVariable ( 0x100 , 2 ) ;
2008-11-14 21:32:20 +00:00
} else {
// GM
2008-11-16 19:20:30 +00:00
setVariable ( 0x100 , 1 ) ;
2008-11-14 21:32:20 +00:00
}
_hotspotTopAction = 0 ;
_hotspotBottomAction = 0 ;
_hotspotRightAction = 0 ;
_hotspotLeftAction = 0 ;
2008-11-15 11:23:02 +00:00
_hotspotSlot = ( uint16 ) - 1 ;
2009-03-10 21:54:45 +00:00
_oldInstruction = ( uint16 ) - 1 ;
2009-08-21 13:57:03 +00:00
_videoSkipAddress = 0 ;
2008-11-14 21:32:20 +00:00
}
Script : : ~ Script ( ) {
delete [ ] _code ;
delete [ ] _savedCode ;
delete _videoFile ;
2021-09-16 09:23:34 +03:00
delete _cellGame ;
2018-01-13 23:50:30 +01:00
delete _tlcGame ;
2008-11-14 21:32:20 +00:00
}
2008-11-16 19:20:30 +00:00
void Script : : setVariable ( uint16 variablenum , byte value ) {
2022-01-04 20:25:00 -06:00
if ( variablenum = = 191 ) {
warning ( " changing var 0x0BF from %d to %d " , ( int ) _variables [ variablenum ] , ( int ) value ) ;
}
debugC ( 1 , kDebugScriptvars , " script variable[0x%03X] = %d (0x%04X), was %d (0x%04X) " , variablenum , value , value , _variables [ variablenum ] , _variables [ variablenum ] ) ;
2008-11-16 19:20:30 +00:00
_variables [ variablenum ] = value ;
}
2021-09-01 19:34:53 -05:00
void Script : : setBitFlag ( int bitnum , bool value ) {
if ( value ) {
_bitflags | = ( 1 < < bitnum ) ;
} else {
_bitflags & = ~ ( 1 < < bitnum ) ;
}
}
bool Script : : getBitFlag ( int bitnum ) {
return _bitflags & ( 1 < < bitnum ) ;
}
2008-11-14 21:32:20 +00:00
void Script : : setDebugger ( Debugger * debugger ) {
_debugger = debugger ;
}
2008-12-30 10:19:16 +00:00
void Script : : timerTick ( ) {
setVariable ( 0x103 , _variables [ 0x103 ] + 1 ) ;
}
2008-11-14 21:32:20 +00:00
bool Script : : loadScript ( Common : : String filename ) {
2021-11-13 23:40:27 +02:00
Common : : SeekableReadStream * scriptfile = nullptr ;
2010-05-11 15:41:31 +00:00
if ( _vm - > _macResFork ) {
// Try to open the script file from the resource fork
scriptfile = _vm - > _macResFork - > getResource ( filename ) ;
} else {
// Try to open the script file
scriptfile = SearchMan . createReadStreamForMember ( filename ) ;
2008-11-14 21:32:20 +00:00
}
2010-05-11 15:41:31 +00:00
if ( ! scriptfile )
return false ;
2008-11-14 21:32:20 +00:00
// Save the script filename
_scriptFile = filename ;
// Load the code
2010-05-11 15:41:31 +00:00
_codeSize = scriptfile - > size ( ) ;
2008-12-24 15:30:31 +00:00
_code = new byte [ _codeSize ] ;
if ( ! _code )
return false ;
2010-05-11 15:41:31 +00:00
scriptfile - > read ( _code , _codeSize ) ;
delete scriptfile ;
2008-11-14 21:32:20 +00:00
2008-12-24 05:41:27 +00:00
// Patch the loaded code for known script bugs
if ( filename . equals ( " dr.grv " ) ) {
2021-02-28 01:28:23 -08:00
// WORKAROUND for the cake puzzle glitch (bug #4050): Lowering the
2008-12-24 05:41:27 +00:00
// piece on the first column and second row updates the wrong script
// variable
2008-12-24 15:30:31 +00:00
assert ( _codeSize = = 5546 ) ;
2008-12-24 05:41:27 +00:00
_code [ 0x03C2 ] = 0x38 ;
2008-12-29 06:23:52 +00:00
} else if ( filename . equals ( " maze.grv " ) ) {
// GRAPHICS ENHANCEMENT - Leave a skeleton in the maze.
2009-01-01 15:06:43 +00:00
// Replaces one normal T intersection with the unused(?)
2008-12-29 06:23:52 +00:00
// skeleton T intersection graphics.
assert ( _codeSize = = 3652 ) ;
// Terminating T branch
_code [ 0x0769 ] = 0x46 ;
_code [ 0x0774 ] = 0x3E ;
_code [ 0x077A ] = 0x42 ;
2009-01-01 15:06:43 +00:00
2008-12-29 06:23:52 +00:00
// T with branch on right
_code [ 0x08E2 ] = 0x43 ;
_code [ 0x08D7 ] = 0x44 ;
_code [ 0x08E8 ] = 0x45 ;
// T with branch on left
_code [ 0x0795 ] = 0x41 ;
_code [ 0x078A ] = 0x40 ;
_code [ 0x079B ] = 0x3F ;
2021-12-05 21:50:29 -06:00
} else if ( _version = = kGroovieT11H & & filename . equals ( " script.grv " ) & & _codeSize = = 62447 ) {
// don't sleep before showing the skulls
memset ( _code + 0x17 , 1 , 0x1F - 0x17 ) ; // set nop
// when the skulls ask you to adjust your brightness, play the song Mr Death
memset ( _code + 0x25 , 1 , 0x2F - 0x25 ) ; // set nop
_code [ 0x25 ] = 0x56 ; // o2_playsound
2021-12-06 04:27:23 -06:00
// o2_playsound resource id 851, uint32
2021-12-05 21:50:29 -06:00
_code [ 0x26 ] = 0x53 ;
_code [ 0x27 ] = 0x03 ;
_code [ 0x28 ] = 0 ;
_code [ 0x29 ] = 0 ;
// o2_playsound loops = 0 for infinite
_code [ 0x2A ] = 0 ;
// o2_playsound val3
_code [ 0x2B ] = 0 ;
2021-12-06 04:27:23 -06:00
} else if ( _version = = kGroovieT11H & & filename . equals ( " itsawrap.grv " ) & & _codeSize = = 517 & & ConfMan . getBool ( " credits_music " ) ) {
// write nops to get rid of MIDI Control Stop and PlaySong
memset ( _code + 0x000 , 1 , 5 ) ; // this one is only a PlaySong
memset ( _code + 0x0B4 , 1 , 10 ) ;
memset ( _code + 0x0136 , 1 , 10 ) ;
memset ( _code + 0x019A , 1 , 10 ) ;
memset ( _code + 0x1FE , 1 , 5 ) ; // this one is only a MIDI Control Stop
// play The Final Hour instead
_code [ 0x00 ] = 0x56 ; // o2_playsound
// o2_playsound resource id 845, uint32
_code [ 0x01 ] = 0x4D ;
_code [ 0x02 ] = 0x03 ;
_code [ 0x03 ] = 0 ;
_code [ 0x04 ] = 0 ;
// o2_playsound loops
_code [ 0x05 ] = 1 ;
// o2_playsound val3
_code [ 0x06 ] = 0 ;
2008-12-24 05:41:27 +00:00
}
2008-11-14 21:32:20 +00:00
// Initialize the script
_currentInstruction = 0 ;
return true ;
}
void Script : : directGameLoad ( int slot ) {
// Reject invalid slots
2018-07-14 04:52:58 -07:00
if ( slot < 0 | | slot > MAX_SAVES - 1 ) {
2008-11-14 21:32:20 +00:00
return ;
}
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " directGameLoad %d " , slot ) ;
2008-11-14 21:32:20 +00:00
2018-11-03 22:56:02 +10:30
// Return to the main script if required
if ( _savedCode ) {
// Returning the correct spot, dealing with _savedVariables, etc
// is not needed as game state is getting nuked anyway
delete [ ] _code ;
_code = _savedCode ;
_codeSize = _savedCodeSize ;
_savedCode = nullptr ;
}
2008-11-14 21:32:20 +00:00
2021-12-05 11:40:33 -06:00
uint16 targetInstruction = 0 ;
2021-11-13 23:40:27 +02:00
const byte * midiInitScript = nullptr ;
2020-07-02 15:24:03 +02:00
uint8 midiInitScriptSize = 0 ;
2014-11-03 11:38:01 +02:00
// HACK: We set the slot to load in the appropriate variable, and set the
// current instruction to the one that actually loads the saved game
// specified in that variable. This differs depending on the game and its
// version.
if ( _version = = kGroovieT7G ) {
// 7th Guest
setVariable ( 0x19 , slot ) ;
2020-07-02 15:24:03 +02:00
targetInstruction = 0x287 ;
// TODO Not sure if this works on or is necessary for Mac or iOS
// versions. Disabling it to prevent breaking game loading.
if ( _vm - > getPlatform ( ) = = Common : : kPlatformDOS ) {
midiInitScript = t7gMidiInitScript ;
midiInitScriptSize = sizeof ( t7gMidiInitScript ) ;
}
2021-10-26 04:32:10 +03:00
} else if ( _version = = kGroovieT11H ) {
2021-11-19 21:06:22 +01:00
setVariable ( 0xF , slot ) ;
2021-10-26 04:32:10 +03:00
_currentInstruction = 0xE78D ;
return ;
2021-10-26 04:50:48 +03:00
} else if ( _version = = kGroovieCDY ) {
setVariable ( 0x1 , slot ) ;
_currentInstruction = 0x9EBF ;
return ;
} else if ( _version = = kGroovieUHP ) {
setVariable ( 0x19 , slot ) ;
_currentInstruction = 0x23B4 ;
return ;
2014-11-03 11:38:01 +02:00
}
2008-11-14 21:32:20 +00:00
2020-07-02 15:24:03 +02:00
if ( midiInitScript & & ! _vm - > _musicPlayer - > isMidiInit ( ) ) {
// Run the MIDI init script as a subscript.
// Backup the current script state
_savedCode = _code ;
_savedCodeSize = _codeSize ;
_savedStacktop = _stacktop ;
_savedScriptFile = _scriptFile ;
// Set the game load instruction as the backup instruction. This
// will run when the subscript returns.
_savedInstruction = targetInstruction ;
// Set the MIDI init script as the current script.
_codeSize = midiInitScriptSize ;
_code = new byte [ _codeSize ] ;
memcpy ( _code , midiInitScript , _codeSize ) ;
_stacktop = 0 ;
_currentInstruction = 0 ;
} else {
// No MIDI initialization necessary. Just jump to the game load
// instruction.
_currentInstruction = targetInstruction ;
// Due to HACK above, the call to check valid save slots is not run.
// As this is where we load save names, manually call it here.
o_checkvalidsaves ( ) ;
}
2008-11-14 21:32:20 +00:00
}
void Script : : step ( ) {
// Prepare the base debug string
2010-11-01 16:02:28 +00:00
_debugString = _scriptFile + Common : : String : : format ( " @0x%04X: " , _currentInstruction ) ;
2008-11-14 21:32:20 +00:00
// Get the current opcode
byte opcode = readScript8bits ( ) ;
_firstbit = ( ( opcode & 0x80 ) ! = 0 ) ;
opcode = opcode & 0x7F ;
// Show the opcode debug string
2010-11-01 16:02:28 +00:00
_debugString + = Common : : String : : format ( " op 0x%02X: " , opcode ) ;
2009-03-10 21:54:45 +00:00
// Only output if we're not re-doing the previous instruction
if ( _currentInstruction ! = _oldInstruction ) {
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " %s " , _debugString . c_str ( ) ) ;
2009-03-10 21:54:45 +00:00
_oldInstruction = _currentInstruction ;
}
2008-11-14 21:32:20 +00:00
// Detect invalid opcodes
if ( opcode > = NUM_OPCODES ) {
o_invalid ( ) ;
return ;
}
// Execute the current opcode
OpcodeFunc op = _opcodes [ opcode ] ;
( this - > * op ) ( ) ;
}
2009-08-21 13:57:03 +00:00
void Script : : setMouseClick ( uint8 button ) {
_eventMouseClicked = button ;
2008-11-14 21:32:20 +00:00
}
void Script : : setKbdChar ( uint8 c ) {
_eventKbdChar = c ;
}
2008-11-15 18:56:39 +00:00
Common : : String & Script : : getContext ( ) {
return _debugString ;
2008-11-14 21:32:20 +00:00
}
2008-12-24 15:30:31 +00:00
uint8 Script : : getCodeByte ( uint16 address ) {
if ( address > = _codeSize )
error ( " Trying to read a script byte at address 0x%04X, while the "
" script is just 0x%04X bytes long " , address , _codeSize ) ;
return _code [ address ] ;
}
2008-11-14 21:32:20 +00:00
uint8 Script : : readScript8bits ( ) {
2008-12-24 15:30:31 +00:00
uint8 data = getCodeByte ( _currentInstruction ) ;
2008-11-14 21:32:20 +00:00
_currentInstruction + + ;
return data ;
}
uint8 Script : : readScriptVar ( ) {
uint8 data = _variables [ readScript8or16bits ( ) ] ;
return data ;
}
uint16 Script : : readScript16bits ( ) {
2009-10-01 15:58:15 +00:00
uint8 lower = readScript8bits ( ) ;
uint8 upper = readScript8bits ( ) ;
return lower | ( upper < < 8 ) ;
2008-11-14 21:32:20 +00:00
}
uint32 Script : : readScript32bits ( ) {
2009-10-01 15:58:15 +00:00
uint16 lower = readScript16bits ( ) ;
uint16 upper = readScript16bits ( ) ;
return lower | ( upper < < 16 ) ;
2008-11-14 21:32:20 +00:00
}
uint16 Script : : readScript8or16bits ( ) {
if ( _firstbit ) {
return readScript8bits ( ) ;
} else {
return readScript16bits ( ) ;
}
}
uint8 Script : : readScriptChar ( bool allow7C , bool limitVal , bool limitVar ) {
uint8 result ;
uint8 data = readScript8bits ( ) ;
if ( limitVal ) {
data & = 0x7F ;
}
2021-11-14 01:48:18 +02:00
if ( allow7C & & ( data = = kVarType2DArray ) ) {
2008-11-14 21:32:20 +00:00
// Index a bidimensional array
uint8 parta , partb ;
parta = readScriptChar ( false , false , false ) ;
partb = readScriptChar ( false , true , true ) ;
result = _variables [ 0x0A * parta + partb + 0x19 ] ;
2021-12-05 11:40:33 -06:00
debugC ( 7 , kDebugScript , " readScriptChar got | for var %d with value %d " , ( int ) ( 0x0A * parta + partb + 0x19 ) , ( int ) result ) ;
2021-11-14 01:48:18 +02:00
} else if ( data = = kVarTypeArray ) {
2008-11-14 21:32:20 +00:00
// Index an array
data = readScript8bits ( ) ;
if ( limitVar ) {
data & = 0x7F ;
}
result = _variables [ data - 0x61 ] ;
2021-12-05 11:40:33 -06:00
debugC ( 7 , kDebugScript , " readScriptChar got # for var %d with value %d " , ( int ) ( data - 0x61 ) , ( int ) result ) ;
2008-11-14 21:32:20 +00:00
} else {
// Immediate value
result = data - 0x30 ;
2021-12-05 11:40:33 -06:00
debugC ( 7 , kDebugScript , " readScriptChar got %d " , ( int ) result ) ;
2008-11-14 21:32:20 +00:00
}
return result ;
}
2018-10-05 23:28:22 +02:00
void Script : : readScriptString ( Common : : String & str ) {
2008-11-14 21:32:20 +00:00
byte c ;
2021-12-05 11:40:33 -06:00
Common : : String orig ;
debugC ( 5 , kDebugScript , " readScriptString start " ) ;
2008-11-14 21:32:20 +00:00
while ( ( c = readScript8bits ( ) ) ) {
2021-12-05 11:40:33 -06:00
orig + = c ;
2008-11-14 21:32:20 +00:00
switch ( c ) {
2021-11-14 01:48:18 +02:00
case kVarTypeArray :
2008-11-14 21:32:20 +00:00
c = readScript8bits ( ) ;
2021-12-05 11:40:33 -06:00
orig + = Common : : String : : format ( " %d " , ( int ) ( c - 0x61 ) ) ;
2008-11-14 21:32:20 +00:00
c = _variables [ c - 0x61 ] + 0x30 ;
2018-12-27 23:15:02 +01:00
if ( _version = = kGroovieT7G ) {
if ( c > = 0x41 & & c < = 0x5A ) {
2021-11-14 01:48:18 +02:00
c + = ' ' ;
2018-12-27 23:15:02 +01:00
}
2008-11-14 21:32:20 +00:00
}
break ;
2021-11-14 01:48:18 +02:00
case kVarType2DArray :
2008-11-14 21:32:20 +00:00
uint8 parta , partb ;
parta = readScriptChar ( false , false , false ) ;
partb = readScriptChar ( false , false , false ) ;
2021-12-05 11:40:33 -06:00
orig + = Common : : String : : format ( " %d " , ( int ) ( 0x0A * parta + partb + 0x19 ) ) ;
2008-11-14 21:32:20 +00:00
c = _variables [ 0x0A * parta + partb + 0x19 ] + 0x30 ;
break ;
default :
2018-12-27 23:15:02 +01:00
if ( _version = = kGroovieT7G ) {
if ( c > = 0x41 & & c < = 0x5A ) {
2021-11-14 01:48:18 +02:00
c + = ' ' ;
2018-12-27 23:15:02 +01:00
}
2008-11-14 21:32:20 +00:00
}
}
// Append the current character at the end of the string
str + = c ;
2022-01-02 23:21:53 -06:00
}
2021-12-05 11:40:33 -06:00
debugC ( 5 , kDebugScript , " readScriptString orig: %s, ret: %s " , orig . c_str ( ) , str . c_str ( ) ) ;
2018-10-05 23:28:22 +02:00
}
uint32 Script : : getVideoRefString ( Common : : String & resName ) {
// Read String from Script (includes variable values)
readScriptString ( resName ) ;
2008-11-14 21:32:20 +00:00
// Add a trailing dot
2021-12-05 11:40:33 -06:00
resName + = ' . ' ;
2008-11-14 21:32:20 +00:00
2022-01-04 20:25:00 -06:00
debugCN ( 1 , kDebugScript , " %s " , resName . c_str ( ) ) ;
2008-11-14 21:32:20 +00:00
// Get the fileref of the resource
2021-10-27 02:11:42 +03:00
return _vm - > _resMan - > getRef ( resName ) ;
2008-11-14 21:32:20 +00:00
}
2021-12-05 11:40:33 -06:00
void Script : : executeInputAction ( uint16 address ) {
debugC ( 1 , kDebugScript , " Groovie::Script: executeInputAction 0x%04X " , ( uint ) address ) ;
// Jump to the planned address
_currentInstruction = address ;
// Exit the input loop
_inputLoopAddress = 0 ;
// Force immediate hiding of the mouse cursor (required when the next video just contains audio)
_vm - > _grvCursorMan - > show ( false ) ;
_vm - > _graphicsMan - > change ( ) ;
}
2008-11-14 21:32:20 +00:00
bool Script : : hotspot ( Common : : Rect rect , uint16 address , uint8 cursor ) {
// Test if the current mouse position is contained in the specified rectangle
Common : : Point mousepos = _vm - > _system - > getEventManager ( ) - > getMousePos ( ) ;
bool contained = rect . contains ( mousepos ) ;
// Show hotspots when debugging
2014-06-05 03:01:12 +01:00
if ( DebugMan . isDebugChannelEnabled ( kDebugHotspots ) ) {
2018-01-13 23:54:59 +01:00
if ( _vm - > _graphicsMan - > isFullScreen ( ) )
2014-11-03 01:43:19 +02:00
rect . translate ( 0 , - 80 ) ;
2018-01-13 23:54:59 +01:00
Graphics : : Surface * gamescreen = _vm - > _system - > lockScreen ( ) ;
gamescreen - > frameRect ( rect , 0xcc2338ff ) ;
_vm - > _system - > unlockScreen ( ) ;
2008-11-14 21:32:20 +00:00
_vm - > _system - > updateScreen ( ) ;
}
if ( contained ) {
// Change the mouse cursor
if ( _newCursorStyle = = 5 ) {
_newCursorStyle = cursor ;
}
// If clicked with the mouse, jump to the specified address
if ( _mouseClicked ) {
2011-04-07 23:36:17 +09:30
_lastCursor = cursor ;
2021-12-05 11:40:33 -06:00
executeInputAction ( address ) ;
2008-11-14 21:32:20 +00:00
}
}
return contained ;
}
void Script : : loadgame ( uint slot ) {
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " loadgame %d " , slot ) ;
2021-11-19 21:06:22 +01:00
// The 11th Hour uses slot 0 for the Open House savegame. It loads this
// savegame before showing the load/restart dialog during the intro. The
// music should not be stopped in this case.
if ( ! ( _vm - > getEngineVersion ( ) = = kGroovieT11H & & slot = = 0 ) )
_vm - > _musicPlayer - > stop ( ) ;
2020-07-27 15:25:05 +02:00
2009-01-13 23:22:47 +00:00
Common : : InSaveFile * file = SaveLoad : : openForLoading ( ConfMan . getActiveDomainName ( ) , slot ) ;
2008-11-14 21:32:20 +00:00
// Loading the variables. It is endian safe because they're byte variables
file - > read ( _variables , 0x400 ) ;
delete file ;
2009-01-14 16:05:26 +00:00
// Hide the mouse cursor
_vm - > _grvCursorMan - > show ( false ) ;
2008-11-14 21:32:20 +00:00
}
2021-09-15 22:50:44 -05:00
bool Script : : preview_loadgame ( uint slot ) { // used by Clandestiny for the photos
Common : : InSaveFile * file = SaveLoad : : openForLoading ( ConfMan . getActiveDomainName ( ) , slot ) ;
if ( ! file )
return false ;
// Loading the variables. It is endian safe because they're byte variables
uint32 size = 21 ;
uint32 bytes_read = file - > read ( _variables , size ) ;
delete file ;
if ( bytes_read < size )
return false ;
return true ;
}
2018-11-03 22:56:02 +10:30
bool Script : : canDirectSave ( ) const {
2021-09-16 21:26:48 +09:30
// Disallow when running a subscript (puzzle)
if ( _savedCode = = nullptr ) {
// UHP appears not to use "room" variables(?)
// 11H uses room plus 'scene' variable. 8D is set to 1 at launch, but scene is left '0' until first nav
// T7G and Clan only use room vars
// TLC uses room variables to indicate question progress
if ( _version = = kGroovieUHP )
return true ;
else if ( _version = = kGroovieT11H )
return _variables [ 0x8C ] ! = 0 | | _variables [ 0x8D ] ! = 1 | | _variables [ 0x8E ] ! = 0 ;
else
return _variables [ 0x8C ] ! = 0 | | _variables [ 0x8D ] ! = 0 ;
}
return false ;
2018-11-03 22:56:02 +10:30
}
2018-07-14 04:52:58 -07:00
void Script : : directGameSave ( int slot , const Common : : String & desc ) {
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " directGameSave %d %s " , slot , desc . c_str ( ) ) ;
2018-07-14 04:52:58 -07:00
if ( slot < 0 | | slot > MAX_SAVES - 1 ) {
return ;
}
const char * saveName = desc . c_str ( ) ;
for ( int i = 0 ; i < 15 ; i + + ) {
_variables [ i ] = saveName [ i ] - 0x30 ;
}
savegame ( slot ) ;
}
2008-11-14 21:32:20 +00:00
void Script : : savegame ( uint slot ) {
2008-12-06 11:01:44 +00:00
char save [ 15 ] ;
char newchar ;
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " savegame %d, canDirectSave: %d " , slot , canDirectSave ( ) ) ;
2009-01-13 23:22:47 +00:00
Common : : OutSaveFile * file = SaveLoad : : openForSaving ( ConfMan . getActiveDomainName ( ) , slot ) ;
2008-11-14 21:32:20 +00:00
2011-04-25 07:04:40 +01:00
if ( ! file ) {
2014-06-05 03:01:12 +01:00
debugC ( 9 , kDebugScript , " Save file pointer is null " ) ;
2011-06-13 22:19:18 +01:00
GUI : : MessageDialog dialog ( _ ( " Failed to save game " ) , _ ( " OK " ) ) ;
2011-04-25 07:04:40 +01:00
dialog . runModal ( ) ;
return ;
}
2022-01-04 20:25:00 -06:00
// HACK: intermittent bug, I think 0x0BF is supposed to be for open house mode, only in save slot 0
bool fixed = false ;
if ( slot ! = 0 & & _variables [ 191 ] = = 1 & & _version = = kGroovieT11H ) {
warning ( " fixing variable 0x0BF " ) ;
_variables [ 191 ] = 0 ;
fixed = true ;
}
2008-11-14 21:32:20 +00:00
// Saving the variables. It is endian safe because they're byte variables
file - > write ( _variables , 0x400 ) ;
2009-01-13 23:22:47 +00:00
delete file ;
2022-01-04 20:25:00 -06:00
// HACK: hopefully this will help us track it down
if ( fixed ) {
g_system - > messageBox ( LogMessageType : : kWarning , " fixed invalid save, please share your log file with us " ) ;
g_system - > displayLogFile ( ) ;
}
2009-01-13 23:22:47 +00:00
// Cache the saved name
2008-12-06 11:01:44 +00:00
for ( int i = 0 ; i < 15 ; i + + ) {
newchar = _variables [ i ] + 0x30 ;
2018-11-03 17:46:57 +00:00
if ( ( newchar < 0x30 | | newchar > 0x39 ) & & ( newchar < 0x41 | | newchar > 0x7A ) & & newchar ! = 0x2E ) {
2009-01-01 15:06:43 +00:00
save [ i ] = ' \0 ' ;
2008-12-06 11:01:44 +00:00
break ;
2018-11-03 17:46:57 +00:00
} else if ( newchar = = 0x2E ) { // '.', generated when space is pressed
save [ i ] = ' ' ;
2008-12-06 11:01:44 +00:00
} else {
save [ i ] = newchar ;
}
}
_saveNames [ slot ] = save ;
2008-11-14 21:32:20 +00:00
}
2010-06-07 17:14:42 +00:00
void Script : : printString ( Graphics : : Surface * surface , const char * str ) {
char message [ 15 ] ;
memset ( message , 0 , 15 ) ;
// Preprocess the string
for ( int i = 0 ; i < 14 ; i + + ) {
if ( str [ i ] < = 0x00 | | str [ i ] = = 0x24 )
break ;
message [ i ] = str [ i ] ;
}
Common : : rtrim ( message ) ;
2022-01-02 23:21:53 -06:00
2010-06-07 17:14:42 +00:00
// Draw the string
2018-10-05 23:28:22 +02:00
if ( _version = = kGroovieT7G ) {
_vm - > _font - > drawString ( surface , message , 0 , 16 , 640 , 0xE2 , Graphics : : kTextAlignCenter ) ;
} else {
2022-01-02 23:21:53 -06:00
_vm - > _videoPlayer - > drawString ( Common : : String ( message ) , 190 , 190 , _vm - > _pixelFormat . RGBToColor ( 0xff , 0x0A , 0x0A ) ) ;
2018-10-05 23:28:22 +02:00
}
2010-06-07 17:14:42 +00:00
}
2008-11-14 21:32:20 +00:00
// OPCODES
void Script : : o_invalid ( ) {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Invalid opcode " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_nop ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: NOP " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_nop8 ( ) {
uint8 tmp = readScript8bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: NOP8: 0x%02X " , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_nop16 ( ) {
uint16 tmp = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: NOP16: 0x%04X " , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_nop32 ( ) {
uint32 tmp = readScript32bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: NOP32: 0x%08X " , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_nop8or16 ( ) {
uint16 tmp = readScript8or16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: NOP8OR16: 0x%04X " , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_playsong ( ) { // 0x02
uint16 fileref = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: PlaySong(0x%04X): Play xmidi file " , fileref ) ;
2008-11-14 21:32:20 +00:00
if ( fileref = = 0x4C17 ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: this song is special somehow " ) ;
2008-11-14 21:32:20 +00:00
// don't save the reference?
}
_vm - > _musicPlayer - > playSong ( fileref ) ;
}
void Script : : o_bf9on ( ) { // 0x03
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF9ON: bitflag 9 turned on " ) ;
2008-11-14 21:32:20 +00:00
_bitflags | = 1 < < 9 ;
}
void Script : : o_palfadeout ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: PALFADEOUT " ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: PALFADEOUT " ) ;
2008-11-14 21:32:20 +00:00
_vm - > _graphicsMan - > fadeOut ( ) ;
}
void Script : : o_bf8on ( ) { // 0x05
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF8ON: bitflag 8 turned on " ) ;
2008-11-14 21:32:20 +00:00
_bitflags | = 1 < < 8 ;
}
void Script : : o_bf6on ( ) { // 0x06
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF6ON: bitflag 6 turned on " ) ;
2008-11-14 21:32:20 +00:00
_bitflags | = 1 < < 6 ;
}
void Script : : o_bf7on ( ) { // 0x07
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF7ON: bitflag 7 turned on " ) ;
2008-11-14 21:32:20 +00:00
_bitflags | = 1 < < 7 ;
}
2021-09-08 18:51:26 -05:00
void Script : : o2_bf0on ( ) { // v2 0x0A
debugC ( 1 , kDebugScript , " Groovie::Script: BF0ON: bitflag 0 turned on " ) ;
_bitflags | = 1 ;
}
2008-11-14 21:32:20 +00:00
void Script : : o_setbackgroundsong ( ) { // 0x08
uint16 fileref = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SetBackgroundSong(0x%04X) " , fileref ) ;
2008-11-14 21:32:20 +00:00
_vm - > _musicPlayer - > setBackgroundSong ( fileref ) ;
}
void Script : : o_videofromref ( ) { // 0x09
uint16 fileref = readScript16bits ( ) ;
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: VIDEOFROMREF(0x%04X) (Not fully imp): Play video file from ref " , fileref ) ;
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d via 0x09 (VideoFromRef) " , _currentInstruction - 3 , fileref ) ;
2008-11-14 21:32:20 +00:00
}
switch ( fileref ) {
case 0x1C03 : // Trilobyte logo
case 0x1C04 : // Virgin logo
case 0x1C05 : // Credits
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: Use external file if available " ) ;
2008-11-14 21:32:20 +00:00
}
break ;
2009-01-01 15:06:43 +00:00
2008-11-14 21:32:20 +00:00
case 0x400D : // floating objects in music room
case 0x5060 : // a sound from gamwav?
2009-03-01 09:17:05 +00:00
case 0x5098 : // a sound from gamwav?
2008-11-14 21:32:20 +00:00
case 0x2402 : // House becomes book in intro?
case 0x1426 : // Turn to face front in hall: played after intro
case 0x206D : // Cards on table puzzle (bedroom)
case 0x2001 : // Coins on table puzzle (bedroom)
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: (This video is special somehow!) " ) ;
warning ( " Groovie::Script: (This video (0x%04X) is special somehow!) " , fileref ) ;
2008-11-14 21:32:20 +00:00
}
2021-09-15 19:28:59 +03:00
break ;
2021-09-15 22:59:32 +03:00
case 0x2420 : // load from the main menu
2021-09-15 19:28:59 +03:00
if ( _version = = kGroovieT7G & & ! ConfMan . getBool ( " originalsaveload " ) ) {
2021-09-15 22:59:32 +03:00
GUI : : SaveLoadChooser * dialog = new GUI : : SaveLoadChooser ( _ ( " Restore game: " ) , _ ( " Restore " ) , false ) ;
2021-09-15 19:28:59 +03:00
int slot = dialog - > runModalWithCurrentTarget ( ) ;
delete dialog ;
if ( slot > = 0 ) {
_currentInstruction = 0x287 ;
_bitflags = 0 ;
setVariable ( 0x19 , slot ) ;
} else {
_currentInstruction = 0x016 ; // back to main menu (load game / new game)
}
return ;
}
break ;
2019-10-19 19:53:15 +01:00
2021-09-15 22:59:32 +03:00
case 0x2422 : // save from the in-game menu
if ( _version = = kGroovieT7G & & ! ConfMan . getBool ( " originalsaveload " ) ) {
GUI : : MessageDialog saveOrLoad ( _ ( " Would you like to save or restore a game? " ) , _ ( " Save " ) , _ ( " Restore " ) ) ;
int choice = saveOrLoad . runModal ( ) ;
if ( choice = = GUI : : kMessageOK ) {
// Save
GUI : : SaveLoadChooser * dialog = new GUI : : SaveLoadChooser ( _ ( " Save game: " ) , _ ( " Save " ) , true ) ;
int slot = dialog - > runModalWithCurrentTarget ( ) ;
Common : : String saveName = dialog - > getResultString ( ) ;
delete dialog ;
if ( slot > = 0 ) {
directGameSave ( slot , saveName ) ;
}
_currentInstruction = 0x17C8 ; // back to game menu
} else {
// Restore
GUI : : SaveLoadChooser * dialog = new GUI : : SaveLoadChooser ( _ ( " Restore game: " ) , _ ( " Restore " ) , false ) ;
int slot = dialog - > runModalWithCurrentTarget ( ) ;
delete dialog ;
if ( slot > = 0 ) {
_currentInstruction = 0x287 ;
_bitflags = 0 ;
setVariable ( 0x19 , slot ) ;
} else {
_currentInstruction = 0x17C8 ; // back to game menu
}
}
return ;
}
break ;
2019-10-19 19:53:15 +01:00
default :
break ;
2008-11-14 21:32:20 +00:00
}
if ( fileref ! = _videoRef ) {
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " \n " ) ;
2008-11-14 21:32:20 +00:00
}
2020-02-25 20:45:15 +01:00
2020-06-26 16:27:33 +02:00
// Determine if the MT-32 or GM initialization video is being played
2021-09-13 01:09:00 +03:00
const bool enhancedMusicTracksExist = _version = = kGroovieT7G & & Common : : File : : exists ( " gu16.ogg " ) ;
const bool gmInitVideo = _version = = kGroovieT7G & & fileref = = 0x2460 & & ! enhancedMusicTracksExist ;
const bool mt32InitVideo = _version = = kGroovieT7G & & fileref = = 0x2461 & & ! enhancedMusicTracksExist ;
2008-11-14 21:32:20 +00:00
// Play the video
2020-06-26 16:27:33 +02:00
// If a MIDI init video is being played, loop it until the "audio"
2020-02-25 20:45:15 +01:00
// (init commands) has finished playing
2020-06-26 16:27:33 +02:00
if ( ! playvideofromref ( fileref , gmInitVideo | | mt32InitVideo ) ) {
2008-11-14 21:32:20 +00:00
// Move _currentInstruction back
_currentInstruction - = 3 ;
2020-07-02 15:24:03 +02:00
} else if ( gmInitVideo | | mt32InitVideo ) {
// MIDI initialization has completed. Set this on the music player,
// so that MIDI init will not be done again on game load.
_vm - > _musicPlayer - > setMidiInit ( true ) ;
if ( gmInitVideo )
// The script plays the GM init video twice to give the "audio"
// enough time to play. It has just looped until the audio finished,
// so the second play is no longer necessary.
// Skip the next instruction.
_currentInstruction + = 3 ;
2008-11-14 21:32:20 +00:00
}
}
2020-02-25 20:45:15 +01:00
bool Script : : playvideofromref ( uint32 fileref , bool loopUntilAudioDone ) {
2008-11-14 21:32:20 +00:00
// It isn't the current video, open it
if ( fileref ! = _videoRef ) {
// Debug bitflags
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: Play video 0x%04X (bitflags: " , fileref ) ;
2008-11-30 21:17:58 +00:00
for ( int i = 15 ; i > = 0 ; i - - ) {
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " %d " , _bitflags & ( 1 < < i ) ? 1 : 0 ) ;
2008-11-30 21:17:58 +00:00
if ( i % 4 = = 0 ) {
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " " ) ;
2008-11-30 21:17:58 +00:00
}
2008-11-14 21:32:20 +00:00
}
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " <- 0) " ) ;
2008-11-14 21:32:20 +00:00
// Close the previous video file
if ( _videoFile ) {
2021-09-11 02:14:50 -05:00
_videoRef = UINT_MAX ;
2008-11-14 21:32:20 +00:00
delete _videoFile ;
}
2021-12-05 11:59:00 -06:00
if ( fileref = = UINT_MAX )
return true ;
2008-11-14 21:32:20 +00:00
// Try to open the new file
2021-10-27 16:42:08 +10:30
ResInfo resInfo ;
if ( ! _vm - > _resMan - > getResInfo ( fileref , resInfo ) ) {
error ( " Groovie::Script: Couldn't find resource info for fileref %d " , fileref ) ;
return true ;
}
_videoFile = _vm - > _resMan - > open ( resInfo ) ;
2008-11-14 21:32:20 +00:00
if ( _videoFile ) {
_videoRef = fileref ;
2011-11-29 22:29:32 +10:30
// If teeth or mask cursor, and in main script, mark video prefer low-speed.
// Filename check as sometimes teeth used for puzzle movements (bishops)
if ( _version = = kGroovieT7G & & ( _lastCursor = = 7 | | _lastCursor = = 4 ) & & _scriptFile = = " script.grv " )
2011-04-07 23:36:17 +09:30
_bitflags | = ( 1 < < 15 ) ;
2021-10-27 16:42:08 +10:30
// act, door and trailer use a variation of motion blocks in the ROQ decoder.
// Original clan engine specifically references these files by name to set the flag
else if ( _version = = kGroovieCDY & & ( resInfo . filename . hasPrefix ( " act " ) | | resInfo . filename . hasPrefix ( " door " ) ) )
_bitflags | = ( 1 < < 14 ) ;
2008-11-14 21:32:20 +00:00
_vm - > _videoPlayer - > load ( _videoFile , _bitflags ) ;
} else {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Couldn't open file " ) ;
2008-11-14 21:32:20 +00:00
return true ;
}
2009-08-21 13:57:03 +00:00
// Reset the clicked mouse events
_eventMouseClicked = 0 ;
}
// Check if the user wants to skip the video
if ( ( _eventMouseClicked = = 2 ) & & ( _videoSkipAddress ! = 0 ) ) {
// Jump to the given address
_currentInstruction = _videoSkipAddress ;
// Reset the skip address
_videoSkipAddress = 0 ;
2020-02-25 20:45:15 +01:00
_bitflags = 0 ;
2009-08-21 13:57:03 +00:00
// End the playback
return true ;
2021-09-07 23:48:48 -05:00
} else if ( _eventMouseClicked = = 2 ) {
_vm - > _videoPlayer - > fastForward ( ) ;
2021-09-08 18:30:26 -05:00
_eventMouseClicked = 0 ;
2008-11-14 21:32:20 +00:00
}
// Video available, play one frame
if ( _videoFile ) {
bool endVideo = _vm - > _videoPlayer - > playFrame ( ) ;
2009-08-05 13:57:40 +00:00
_vm - > _musicPlayer - > frameTick ( ) ;
2008-11-14 21:32:20 +00:00
2020-02-25 20:45:15 +01:00
if ( endVideo & & loopUntilAudioDone & & _vm - > _musicPlayer - > isPlaying ( ) ) {
// The video has ended, but the audio hasn't. Loop the video.
_videoFile - > seek ( 0 ) ;
// Clear bit flag 9 (fade-in)
_vm - > _videoPlayer - > load ( _videoFile , _bitflags & ~ ( 1 < < 9 ) ) ;
return false ;
}
if ( endVideo | | ( loopUntilAudioDone & & ! _vm - > _musicPlayer - > isPlaying ( ) ) ) {
// The video has ended, or it was being looped and the audio has ended.
2008-11-14 21:32:20 +00:00
// Close the file
delete _videoFile ;
2021-11-13 23:40:27 +02:00
_videoFile = nullptr ;
2021-09-11 02:14:50 -05:00
_videoRef = UINT_MAX ;
2008-11-14 21:32:20 +00:00
// Clear the input events while playing the video
2009-08-21 13:57:03 +00:00
_eventMouseClicked = 0 ;
2008-11-14 21:32:20 +00:00
_eventKbdChar = 0 ;
// Newline
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " \n " ) ;
2020-02-25 20:45:15 +01:00
_bitflags = 0 ;
// Let the caller know if the video has ended
return true ;
2008-11-14 21:32:20 +00:00
}
2020-02-25 20:45:15 +01:00
// The video has not ended yet.
return false ;
2008-11-14 21:32:20 +00:00
}
// If the file is closed, finish the playback
2020-02-25 20:45:15 +01:00
_bitflags = 0 ;
2008-11-14 21:32:20 +00:00
return true ;
}
2021-09-01 19:34:53 -05:00
bool Script : : playBackgroundSound ( uint32 fileref , uint32 loops ) {
2021-09-11 02:14:50 -05:00
if ( fileref = = UINT_MAX ) {
2021-09-01 19:34:53 -05:00
return false ;
}
// Try to open the new file
Common : : SeekableReadStream * _soundFile = _vm - > _resMan - > open ( fileref ) ;
if ( _soundFile ) {
_vm - > _soundQueue . queue ( _soundFile , loops ) ;
} else {
2021-09-10 23:51:22 -05:00
warning ( " Groovie::Script: Couldn't open file " ) ;
2021-09-01 19:34:53 -05:00
return false ;
}
return true ;
}
2008-11-14 21:32:20 +00:00
void Script : : o_bf5on ( ) { // 0x0A
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF5ON: bitflag 5 turned on " ) ;
2008-11-14 21:32:20 +00:00
_bitflags | = 1 < < 5 ;
}
2009-02-15 19:52:44 +00:00
void Script : : o_inputloopstart ( ) { //0x0B
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: Input loop start " ) ;
2008-11-14 21:32:20 +00:00
2018-01-13 23:50:30 +01:00
// For TLC the regions for many questions are in an extra database. Reset internal region counters
2021-11-13 23:40:27 +02:00
if ( _version = = kGroovieTLC & & _tlcGame ! = nullptr ) {
2021-09-12 22:43:42 -05:00
# ifdef ENABLE_GROOVIE2
2018-01-13 23:50:30 +01:00
_tlcGame - > getRegionRewind ( ) ;
2021-09-12 22:43:42 -05:00
# endif
2018-01-13 23:50:30 +01:00
}
2021-12-05 11:40:33 -06:00
// Reset the mouse cursor
2008-11-14 21:32:20 +00:00
_newCursorStyle = 5 ;
// Save the input loop address
_inputLoopAddress = _currentInstruction - 1 ;
// Save the current mouse state for the whole loop
2009-08-21 13:57:03 +00:00
_mouseClicked = ( _eventMouseClicked = = 1 ) ;
_eventMouseClicked = 0 ;
2008-11-14 21:32:20 +00:00
// Save the current pressed character for the whole loop
_kbdChar = _eventKbdChar ;
_eventKbdChar = 0 ;
}
void Script : : o_keyboardaction ( ) {
uint8 val = readScript8bits ( ) ;
uint16 address = readScript16bits ( ) ;
// Check the typed key
if ( _kbdChar = = val ) {
2022-01-14 00:51:09 -06:00
debugC ( 1 , kDebugScript , " Groovie::Script: Test key == %c (0x%02X) @0x%04X - match " , val , val , address ) ;
2018-01-13 23:54:59 +01:00
2021-12-05 11:40:33 -06:00
executeInputAction ( address ) ;
2018-01-13 23:54:59 +01:00
} else {
2022-01-14 00:51:09 -06:00
debugC ( 5 , kDebugScript , " Groovie::Script: Test key == %c (0x%02X) @0x%04X " , val , val , address ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_hotspot_rect ( ) {
uint16 left = readScript16bits ( ) ;
uint16 top = readScript16bits ( ) ;
uint16 right = readScript16bits ( ) ;
uint16 bottom = readScript16bits ( ) ;
uint16 address = readScript16bits ( ) ;
uint8 cursor = readScript8bits ( ) ;
2018-01-13 23:50:30 +01:00
// TLC: The regions for many questions are in an extra database
2021-11-13 23:40:27 +02:00
if ( _version = = kGroovieTLC & & left = = 0 & & top = = 0 & & right = = 0 & & bottom = = 0 & & _tlcGame ! = nullptr ) {
2021-09-12 22:43:42 -05:00
# ifdef ENABLE_GROOVIE2
2018-01-13 23:50:30 +01:00
if ( _tlcGame - > getRegionNext ( left , top , right , bottom ) < 0 ) {
2021-09-11 02:14:50 -05:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d SKIPPED " , left , top , right , bottom , address , cursor ) ;
2018-01-13 23:50:30 +01:00
return ;
}
2021-09-12 22:43:42 -05:00
# endif
2018-01-13 23:50:30 +01:00
}
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d " , left , top , right , bottom , address , cursor ) ;
2008-11-14 21:32:20 +00:00
// Mark the specified rectangle
Common : : Rect rect ( left , top , right , bottom ) ;
hotspot ( rect , address , cursor ) ;
}
void Script : : o_hotspot_left ( ) {
uint16 address = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-LEFT @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
// Mark the leftmost 100 pixels of the game area
Common : : Rect rect ( 0 , 80 , 100 , 400 ) ;
hotspot ( rect , address , 1 ) ;
}
void Script : : o_hotspot_right ( ) {
uint16 address = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-RIGHT @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
// Mark the rightmost 100 pixels of the game area
Common : : Rect rect ( 540 , 80 , 640 , 400 ) ;
hotspot ( rect , address , 2 ) ;
}
void Script : : o_hotspot_center ( ) {
uint16 address = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-CENTER @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
2011-04-14 14:34:28 +02:00
// Mark the centermost 240 pixels of the game area
2008-11-14 21:32:20 +00:00
Common : : Rect rect ( 200 , 80 , 440 , 400 ) ;
hotspot ( rect , address , 0 ) ;
}
void Script : : o_hotspot_current ( ) {
2009-03-01 09:17:05 +00:00
uint16 address = readScript16bits ( ) ;
2008-11-14 21:32:20 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-CURRENT @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
2009-03-01 09:17:05 +00:00
// The original interpreter doesn't check the position, so accept the
// whole screen
Common : : Rect rect ( 0 , 0 , 640 , 480 ) ;
hotspot ( rect , address , 0 ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_inputloopend ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: Input loop end " ) ;
2008-11-14 21:32:20 +00:00
// Handle the predefined hotspots
if ( _hotspotTopAction ) {
Common : : Rect rect ( 0 , 0 , 640 , 80 ) ;
hotspot ( rect , _hotspotTopAction , _hotspotTopCursor ) ;
}
if ( _hotspotBottomAction ) {
Common : : Rect rect ( 0 , 400 , 640 , 480 ) ;
hotspot ( rect , _hotspotBottomAction , _hotspotBottomCursor ) ;
}
if ( _hotspotRightAction ) {
Common : : Rect rect ( 560 , 0 , 640 , 480 ) ;
hotspot ( rect , _hotspotRightAction , 2 ) ;
}
if ( _hotspotLeftAction ) {
Common : : Rect rect ( 0 , 0 , 80 , 480 ) ;
hotspot ( rect , _hotspotLeftAction , 1 ) ;
}
// Nothing to do
if ( _inputLoopAddress ) {
2021-12-30 22:06:35 -06:00
uint16 newCursor = _newCursorStyle ;
if ( _variables [ 0x91 ] = = 1 ) {
newCursor | = 0x8000 ;
}
if ( newCursor ! = _vm - > _grvCursorMan - > getStyle ( ) ) {
_vm - > _grvCursorMan - > setStyle ( newCursor ) ;
2008-11-14 21:32:20 +00:00
}
2009-01-14 03:09:19 +00:00
_vm - > _grvCursorMan - > show ( true ) ;
2008-11-14 21:32:20 +00:00
// Go back to the begining of the loop
_currentInstruction = _inputLoopAddress ;
// There's nothing to do until we get some input
_vm - > waitForInput ( ) ;
}
}
void Script : : o_random ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 maxnum = readScript8bits ( ) ;
2022-01-05 16:42:46 -06:00
byte oldVal = _variables [ varnum ] ;
2008-11-14 21:32:20 +00:00
2018-10-05 23:28:22 +02:00
// TODO: Check if this is really different between the Engines
if ( _version = = kGroovieT7G ) {
setVariable ( varnum , _random . getRandomNumber ( maxnum ) ) ;
} else {
2021-08-26 22:18:45 -05:00
setVariable ( varnum , _random . getRandomNumber ( maxnum - 1 ) ) ;
2018-10-05 23:28:22 +02:00
}
2022-01-05 16:42:46 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: RANDOM: var[0x%04X] = rand(%d), changed from %d to %d " , varnum , maxnum , oldVal , _variables [ varnum ] ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_jmp ( ) {
uint16 address = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: JMP @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
// Set the current address
_currentInstruction = address ;
}
void Script : : o_loadstring ( ) {
uint16 varnum = readScript8or16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: LOADSTRING var[0x%04X..] = " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2008-11-16 19:20:30 +00:00
setVariable ( varnum + + , readScriptChar ( true , true , true ) ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , _variables [ varnum - 1 ] ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " \n " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_ret ( ) {
uint8 val = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: RET %d " , val ) ;
2008-11-14 21:32:20 +00:00
// Set the return value
2008-11-16 19:20:30 +00:00
setVariable ( 0x102 , val ) ;
2008-11-14 21:32:20 +00:00
// Get the return address
if ( _stacktop > 0 ) {
_stacktop - - ;
_currentInstruction = _stack [ _stacktop ] ;
} else {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Return: Stack is empty " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_call ( ) {
uint16 address = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: CALL @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
// Save return address in the call stack
_stack [ _stacktop ] = _currentInstruction ;
_stacktop + + ;
// Change the current instruction
_currentInstruction = address ;
}
void Script : : o_sleep ( ) {
uint16 time = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SLEEP 0x%04X (%d ms) " , time , time * 3 ) ;
2008-11-14 21:32:20 +00:00
2021-10-23 16:56:06 +03:00
uint32 endTime = _vm - > _system - > getMillis ( ) + time * 3 ;
Common : : Event ev ;
while ( _vm - > _system - > getMillis ( ) < endTime ) {
_vm - > _system - > getEventManager ( ) - > pollEvent ( ev ) ;
_vm - > _system - > updateScreen ( ) ;
_vm - > _system - > delayMillis ( 10 ) ;
}
2008-11-14 21:32:20 +00:00
}
void Script : : o_strcmpnejmp ( ) { // 0x1A
uint16 varnum = readScript8or16bits ( ) ;
uint8 result = 1 ;
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: STRCMP-NEJMP: var[0x%04X..], " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2009-10-26 19:06:36 +00:00
uint8 val = readScriptChar ( true , true , true ) ;
2008-11-14 21:32:20 +00:00
if ( _variables [ varnum ] ! = val ) {
result = 0 ;
}
varnum + + ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , val ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
uint16 address = readScript16bits ( ) ;
if ( ! result ) {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " jumping to @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_currentInstruction = address ;
} else {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " not jumping " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_xor_obfuscate ( ) {
uint16 varnum = readScript8or16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: XOR OBFUSCATE: var[0x%04X..] = " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
uint8 val = readScript8bits ( ) ;
_firstbit = ( ( val & 0x80 ) ! = 0 ) ;
val & = 0x4F ;
2008-11-16 19:20:30 +00:00
setVariable ( varnum , _variables [ varnum ] ^ val ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " %c " , _variables [ varnum ] ) ;
2008-11-14 21:32:20 +00:00
varnum + + ;
} while ( ! _firstbit ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " \n " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_vdxtransition ( ) { // 0x1C
uint16 fileref = readScript16bits ( ) ;
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: VDX transition fileref = 0x%04X " , fileref ) ;
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d via 0x1C (VdxTransition) " , _currentInstruction - 3 , fileref ) ;
2008-11-14 21:32:20 +00:00
}
// Set bit 1
_bitflags | = 1 < < 1 ;
// Clear bit 7
_bitflags & = ~ ( 1 < < 7 ) ;
// Set bit 2 if _firstbit
if ( _firstbit ) {
_bitflags | = 1 < < 2 ;
}
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction - = 3 ;
}
}
void Script : : o_swap ( ) {
uint16 varnum1 = readScript8or16bits ( ) ;
uint16 varnum2 = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SWAP var[0x%04X] <-> var[0x%04X] " , varnum1 , varnum2 ) ;
2008-11-14 21:32:20 +00:00
uint8 tmp = _variables [ varnum1 ] ;
2008-11-16 19:20:30 +00:00
setVariable ( varnum1 , _variables [ varnum2 ] ) ;
setVariable ( varnum2 , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_inc ( ) {
uint16 varnum = readScript8or16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: INC var[0x%04X] " , varnum ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum , _variables [ varnum ] + 1 ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_dec ( ) {
uint16 varnum = readScript8or16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: DEC var[0x%04X] " , varnum ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum , _variables [ varnum ] - 1 ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_strcmpnejmp_var ( ) { // 0x21
uint16 data = readScriptVar ( ) ;
2009-01-01 15:06:43 +00:00
2008-11-14 21:32:20 +00:00
if ( data > 9 ) {
data - = 7 ;
}
data = _variables [ data + 0x19 ] ;
bool stringsmatch = 1 ;
do {
if ( _variables [ data + + ] ! = readScriptChar ( true , true , true ) ) {
stringsmatch = 0 ;
2009-01-01 15:06:43 +00:00
}
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
uint16 offset = readScript16bits ( ) ;
if ( ! stringsmatch ) {
_currentInstruction = offset ;
}
}
2021-08-26 20:58:10 -05:00
void Script : : o_copybgtofg ( ) { // 0x22
debugC ( 1 , kDebugScript , " Groovie::Script: COPY_BG_TO_FG " ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: COPY_BG_TO_FG " , _currentInstruction - 1 ) ;
2021-09-10 23:51:22 -05:00
size_t len = _vm - > _graphicsMan - > _foreground . pitch * _vm - > _graphicsMan - > _foreground . h ;
memcpy ( _vm - > _graphicsMan - > _foreground . getPixels ( ) , _vm - > _graphicsMan - > _background . getPixels ( ) , len ) ;
2021-08-26 20:58:10 -05:00
}
2018-12-27 23:15:02 +01:00
2021-08-26 20:58:10 -05:00
void Script : : o2_copybgtofg ( ) { // 0x22
debugC ( 1 , kDebugScript , " Groovie::Script: COPY_SCREEN_TO_BG " ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: COPY_SCREEN_TO_BG " , _currentInstruction - 1 ) ;
Graphics : : Surface * screen = _vm - > _system - > lockScreen ( ) ;
if ( _vm - > _graphicsMan - > isFullScreen ( ) ) {
_vm - > _graphicsMan - > _foreground . copyFrom ( screen - > getSubArea ( Common : : Rect ( 0 , 0 , 640 , 480 ) ) ) ;
} else {
_vm - > _graphicsMan - > _foreground . copyFrom ( screen - > getSubArea ( Common : : Rect ( 0 , 80 , 640 , 400 ) ) ) ;
2018-12-27 23:15:02 +01:00
}
2021-08-26 20:58:10 -05:00
_vm - > _system - > unlockScreen ( ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_strcmpeqjmp ( ) { // 0x23
uint16 varnum = readScript8or16bits ( ) ;
uint8 result = 1 ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: STRCMP-EQJMP: var[0x%04X..], " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2009-10-26 19:06:36 +00:00
uint8 val = readScriptChar ( true , true , true ) ;
2008-11-14 21:32:20 +00:00
if ( _variables [ varnum ] ! = val ) {
result = 0 ;
}
varnum + + ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , val ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
uint16 address = readScript16bits ( ) ;
if ( result ) {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " jumping to @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_currentInstruction = address ;
} else {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " not jumping " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_mov ( ) {
uint16 varnum1 = readScript8or16bits ( ) ;
uint16 varnum2 = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: MOV var[0x%04X] = var[0x%04X] " , varnum1 , varnum2 ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum1 , _variables [ varnum2 ] ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_add ( ) {
uint16 varnum1 = readScript8or16bits ( ) ;
uint16 varnum2 = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: ADD var[0x%04X] += var[0x%04X] " , varnum1 , varnum2 ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum1 , _variables [ varnum1 ] + _variables [ varnum2 ] ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_videofromstring1 ( ) {
2018-10-05 23:28:22 +02:00
Common : : String vidName ;
2008-11-14 21:32:20 +00:00
uint16 instStart = _currentInstruction ;
2018-10-05 23:28:22 +02:00
uint32 fileref = getVideoRefString ( vidName ) ;
2008-11-14 21:32:20 +00:00
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2022-01-04 20:25:00 -06:00
debugC ( 1 , kDebugScript , " Groovie::Script: VIDEOFROMSTRING1 %d ('%s') " , fileref , vidName . c_str ( ) ) ;
2018-10-05 23:28:22 +02:00
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d ('%s') via 0x26 (VideoFromString1) " , instStart - 1 , fileref , vidName . c_str ( ) ) ;
2008-11-14 21:32:20 +00:00
}
2021-08-26 20:58:10 -05:00
if ( _version ! = kGroovieT7G ) {
// Clear bit 1
_bitflags & = ~ ( 1 < < 1 ) ;
}
2018-10-05 23:28:22 +02:00
2008-11-14 21:32:20 +00:00
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction = instStart - 1 ;
}
}
void Script : : o_videofromstring2 ( ) {
2018-10-05 23:28:22 +02:00
Common : : String vidName ;
2008-11-14 21:32:20 +00:00
uint16 instStart = _currentInstruction ;
2018-10-05 23:28:22 +02:00
uint32 fileref = getVideoRefString ( vidName ) ;
2008-11-14 21:32:20 +00:00
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2022-01-04 20:25:00 -06:00
debugC ( 1 , kDebugScript , " Groovie::Script: VIDEOFROMSTRING2 %d ('%s') " , fileref , vidName . c_str ( ) ) ;
2018-10-05 23:28:22 +02:00
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d ('%s') via 0x27 (VideoFromString2) " , instStart - 1 , fileref , vidName . c_str ( ) ) ;
2008-11-14 21:32:20 +00:00
}
// Set bit 1
_bitflags | = 1 < < 1 ;
// Set bit 2 if _firstbit
if ( _firstbit ) {
_bitflags | = 1 < < 2 ;
}
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction = instStart - 1 ;
}
}
void Script : : o_stopmidi ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: STOPMIDI (TODO) " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_endscript ( ) {
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: END OF SCRIPT " ) ;
2008-11-15 18:56:39 +00:00
_vm - > quitGame ( ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_sethotspottop ( ) {
uint16 address = readScript16bits ( ) ;
uint8 cursor = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: SETHOTSPOTTOP @0x%04X cursor=%d " , address , cursor ) ;
2008-11-14 21:32:20 +00:00
_hotspotTopAction = address ;
_hotspotTopCursor = cursor ;
}
void Script : : o_sethotspotbottom ( ) {
uint16 address = readScript16bits ( ) ;
uint8 cursor = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: SETHOTSPOTBOTTOM @0x%04X cursor=%d " , address , cursor ) ;
2008-11-14 21:32:20 +00:00
_hotspotBottomAction = address ;
_hotspotBottomCursor = cursor ;
}
void Script : : o_loadgame ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 slot = _variables [ varnum ] ;
2009-01-01 15:06:43 +00:00
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: LOADGAME var[0x%04X] -> slot=%d " , varnum , slot ) ;
2008-11-14 21:32:20 +00:00
loadgame ( slot ) ;
2018-01-13 22:53:24 +01:00
if ( _version = = kGroovieT7G ) {
_vm - > _system - > fillScreen ( 0 ) ;
}
2008-11-14 21:32:20 +00:00
}
void Script : : o_savegame ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 slot = _variables [ varnum ] ;
2009-01-01 15:06:43 +00:00
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: SAVEGAME var[0x%04X] -> slot=%d " , varnum , slot ) ;
2008-11-14 21:32:20 +00:00
savegame ( slot ) ;
}
void Script : : o_hotspotbottom_4 ( ) { //0x30
uint16 address = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 5 , kDebugScript , " Groovie::Script: HOTSPOT-BOTTOM @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
// Mark the 80 pixels under the game area
Common : : Rect rect ( 0 , 400 , 640 , 480 ) ;
hotspot ( rect , address , 4 ) ;
}
void Script : : o_midivolume ( ) {
uint16 arg1 = readScript16bits ( ) ;
uint16 arg2 = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: MIDI volume: %d %d " , arg1 , arg2 ) ;
2008-11-14 21:32:20 +00:00
_vm - > _musicPlayer - > setGameVolume ( arg1 , arg2 ) ;
}
void Script : : o_jne ( ) {
int16 varnum1 = readScript8or16bits ( ) ;
uint16 varnum2 = readScript16bits ( ) ;
uint16 address = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: JNE: var[var[0x%04X] - 0x31] != var[0x%04X] @0x%04X " , varnum1 , varnum2 , address ) ;
2008-11-14 21:32:20 +00:00
if ( _variables [ _variables [ varnum1 ] - 0x31 ] ! = _variables [ varnum2 ] ) {
_currentInstruction = address ;
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " jumping to @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
} else {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " not jumping " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_loadstringvar ( ) {
uint16 varnum = readScript8or16bits ( ) ;
2009-01-01 15:06:43 +00:00
2008-11-14 21:32:20 +00:00
varnum = _variables [ varnum ] - 0x31 ;
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: LOADSTRINGVAR var[0x%04X..] = " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2008-11-16 19:20:30 +00:00
setVariable ( varnum + + , readScriptChar ( true , true , true ) ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , _variables [ varnum - 1 ] ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " \n " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_chargreatjmp ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 result = 0 ;
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: CHARGREAT-JMP: var[0x%04X..], " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2009-10-26 19:06:36 +00:00
uint8 val = readScriptChar ( true , true , true ) ;
2008-11-14 21:32:20 +00:00
if ( val < _variables [ varnum ] ) {
result = 1 ;
}
varnum + + ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , val ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
uint16 address = readScript16bits ( ) ;
if ( result ) {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " jumping to @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_currentInstruction = address ;
} else {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " not jumping " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_bf7off ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: BF7OFF: bitflag 7 turned off " ) ;
2008-11-14 21:32:20 +00:00
_bitflags & = ~ ( 1 < < 7 ) ;
}
void Script : : o_charlessjmp ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 result = 0 ;
2018-10-05 23:28:22 +02:00
debugCN ( 1 , kDebugScript , " Groovie::Script: CHARLESS-JMP: var[0x%04X..], " , varnum ) ;
2008-11-14 21:32:20 +00:00
do {
2009-10-26 19:06:36 +00:00
uint8 val = readScriptChar ( true , true , true ) ;
2008-11-14 21:32:20 +00:00
if ( val > _variables [ varnum ] ) {
result = 1 ;
}
varnum + + ;
2014-06-05 03:30:18 +01:00
debugCN ( 1 , kDebugScript , " 0x%02X " , val ) ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
uint16 address = readScript16bits ( ) ;
if ( result ) {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " jumping to @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_currentInstruction = address ;
} else {
2014-06-05 03:30:18 +01:00
debugC ( 1 , kDebugScript , " not jumping " ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_copyrecttobg ( ) { // 0x37
uint16 left = readScript16bits ( ) ;
uint16 top = readScript16bits ( ) ;
uint16 right = readScript16bits ( ) ;
uint16 bottom = readScript16bits ( ) ;
2014-11-03 01:43:19 +02:00
uint16 baseTop = ( ! _vm - > _graphicsMan - > isFullScreen ( ) ) ? 80 : 0 ;
2014-06-02 22:09:53 +01:00
// Sanity checks to prevent bad pointer access crashes
if ( left > right ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT left:%d > right:%d " , left , right ) ;
2014-06-02 22:09:53 +01:00
// swap over left and right parameters
uint16 j ;
j = right ;
right = left ;
left = j ;
}
if ( top > bottom ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT top:%d > bottom:%d " , top , bottom ) ;
2014-06-02 22:09:53 +01:00
// swap over top and bottom parameters
uint16 j ;
j = bottom ;
bottom = top ;
top = j ;
}
2014-11-03 01:43:19 +02:00
if ( top < baseTop ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT top < baseTop... clamping " ) ;
2014-11-03 01:43:19 +02:00
top = baseTop ;
2014-06-02 22:09:53 +01:00
}
if ( top > = 480 ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT top >= 480... clamping " ) ;
2014-06-02 22:09:53 +01:00
top = 480 - 1 ;
}
if ( bottom > = 480 ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT bottom >= 480... clamping " ) ;
2014-06-02 22:09:53 +01:00
bottom = 480 - 1 ;
}
if ( left > = 640 ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT left >= 640... clamping " ) ;
2014-06-02 22:09:53 +01:00
left = 640 - 1 ;
}
if ( right > = 640 ) {
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: COPYRECT right >= 640... clamping " ) ;
2014-06-02 22:09:53 +01:00
right = 640 - 1 ;
}
2021-09-14 01:01:29 -05:00
uint16 width = right - left , height = bottom - top ;
2008-11-14 21:32:20 +00:00
uint32 offset = 0 ;
2018-10-05 23:28:22 +02:00
uint32 pitch = _vm - > _graphicsMan - > _foreground . pitch ;
2008-11-14 21:32:20 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: COPYRECT((%d,%d)->(%d,%d)) " , left , top , right , bottom ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: COPYRECT((%d,%d)->(%d,%d)) " , _currentInstruction - 9 , left , top , right , bottom ) ;
2008-11-14 21:32:20 +00:00
2021-09-14 01:01:29 -05:00
byte * fg = ( byte * ) _vm - > _graphicsMan - > _foreground . getBasePtr ( left , top - baseTop ) ;
byte * bg = ( byte * ) _vm - > _graphicsMan - > _background . getBasePtr ( left , top - baseTop ) ;
for ( uint16 i = 0 ; i < height ; i + + ) {
2018-10-05 23:28:22 +02:00
memcpy ( bg + offset , fg + offset , width * _vm - > _graphicsMan - > _foreground . format . bytesPerPixel ) ;
offset + = pitch ;
2008-11-14 21:32:20 +00:00
}
2018-10-05 23:28:22 +02:00
2021-09-14 01:01:29 -05:00
_vm - > _system - > copyRectToScreen ( bg , pitch , left , top , width , height ) ;
2008-11-14 21:32:20 +00:00
_vm - > _graphicsMan - > change ( ) ;
}
void Script : : o_restorestkpnt ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: Restore stack pointer from saved (TODO) " ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_obscureswap ( ) {
uint16 var1 , var2 , tmp ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: OBSCSWAP " ) ;
2008-11-14 21:32:20 +00:00
// Read the first variable
var1 = readScriptChar ( false , true , true ) * 10 ;
var1 + = readScriptChar ( false , true , true ) + 0x19 ;
// Read the second variable
var2 = readScriptChar ( false , true , true ) * 10 ;
var2 + = readScriptChar ( false , true , true ) + 0x19 ;
// Swap the values
tmp = _variables [ var1 ] ;
2008-11-16 19:20:30 +00:00
setVariable ( var1 , _variables [ var2 ] ) ;
setVariable ( var2 , tmp ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_printstring ( ) {
2009-10-26 19:06:36 +00:00
char stringstorage [ 15 ] ;
2008-11-14 21:32:20 +00:00
uint8 counter = 0 ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: PRINTSTRING " ) ;
2021-08-26 22:18:45 -05:00
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: PRINTSTRING " , _currentInstruction - 1 ) ;
2008-11-14 21:32:20 +00:00
memset ( stringstorage , 0 , 15 ) ;
do {
2009-10-26 19:06:36 +00:00
char newchar = readScriptChar ( true , true , true ) + 0x30 ;
2008-11-14 21:32:20 +00:00
if ( newchar < 0x30 | | newchar > 0x39 ) { // If character is invalid, chuck a space in
if ( newchar < 0x41 | | newchar > 0x7A ) {
newchar = 0x20 ;
}
}
stringstorage [ counter ] = newchar ;
counter + + ;
2008-12-24 15:30:31 +00:00
} while ( ! ( getCodeByte ( _currentInstruction - 1 ) & 0x80 ) ) ;
2008-11-14 21:32:20 +00:00
stringstorage [ counter ] = 0 ;
2010-06-07 17:14:42 +00:00
Common : : Rect topbar ( 640 , 80 ) ;
Graphics : : Surface * gamescreen = _vm - > _system - > lockScreen ( ) ;
// Clear the top bar
gamescreen - > fillRect ( topbar , 0 ) ;
// Draw the string
printString ( gamescreen , stringstorage ) ;
_vm - > _system - > unlockScreen ( ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_hotspot_slot ( ) {
uint16 slot = readScript8bits ( ) ;
uint16 left = readScript16bits ( ) ;
uint16 top = readScript16bits ( ) ;
uint16 right = readScript16bits ( ) ;
uint16 bottom = readScript16bits ( ) ;
uint16 address = readScript16bits ( ) ;
uint16 cursor = readScript8bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: HOTSPOT-SLOT %d (%d,%d,%d,%d) @0x%04X cursor=%d (TODO) " , slot , left , top , right , bottom , address , cursor ) ;
// Set rectangle according to the used engine. To remove the previously written text an the screen.
Common : : Rect removeText ;
if ( _version = = kGroovieT7G ) {
removeText . left = 0 ;
removeText . top = 0 ;
removeText . right = 640 ;
removeText . bottom = 80 ;
} else {
// Only tested for 11th hour. TLC does not use this command.
removeText . left = 120 ;
removeText . top = 185 ;
removeText . right = 400 ;
removeText . bottom = 215 ;
}
2008-11-14 21:32:20 +00:00
Common : : Rect rect ( left , top , right , bottom ) ;
if ( hotspot ( rect , address , cursor ) ) {
2008-12-06 11:01:44 +00:00
if ( _hotspotSlot = = slot ) {
return ;
2008-11-14 21:32:20 +00:00
}
2010-06-07 17:14:42 +00:00
Graphics : : Surface * gamescreen = _vm - > _system - > lockScreen ( ) ;
// Clear the top bar
2018-10-05 23:28:22 +02:00
gamescreen - > fillRect ( removeText , 0 ) ; // 0 works for both color formats (Groovie V1 and V2)
2010-06-07 17:14:42 +00:00
printString ( gamescreen , _saveNames [ slot ] . c_str ( ) ) ;
_vm - > _system - > unlockScreen ( ) ;
2008-11-15 11:23:02 +00:00
// Save the currently highlighted slot
_hotspotSlot = slot ;
2018-10-05 23:28:22 +02:00
_vm - > _graphicsMan - > change ( ) ;
2008-11-14 21:32:20 +00:00
} else {
2008-11-15 11:23:02 +00:00
if ( _hotspotSlot = = slot ) {
2008-11-14 21:32:20 +00:00
Graphics : : Surface * gamescreen ;
gamescreen = _vm - > _system - > lockScreen ( ) ;
2018-10-05 23:28:22 +02:00
gamescreen - > fillRect ( removeText , 0 ) ; // 0 works for both color formats (Groovie V1 and V2)
2008-11-14 21:32:20 +00:00
_vm - > _system - > unlockScreen ( ) ;
2008-11-15 11:23:02 +00:00
// Removing the slot highlight
_hotspotSlot = ( uint16 ) - 1 ;
2018-10-05 23:28:22 +02:00
_vm - > _graphicsMan - > change ( ) ;
2008-11-14 21:32:20 +00:00
}
}
}
2018-01-13 23:50:30 +01:00
// Checks valid save games. Even for TLC (uses only 4 user save games) the function
// checks for 10 save games.
2008-11-14 21:32:20 +00:00
void Script : : o_checkvalidsaves ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: CHECKVALIDSAVES " ) ;
2022-01-04 20:25:00 -06:00
const int maxSaves = 10 ; // max number of saves that the original games expect
2008-11-14 21:32:20 +00:00
2009-01-13 23:22:47 +00:00
// Reset the array of valid saves and the savegame names cache
2018-07-14 04:52:58 -07:00
for ( int i = 0 ; i < MAX_SAVES ; i + + ) {
2022-01-04 20:25:00 -06:00
if ( i < maxSaves )
setVariable ( i , 0 ) ;
2009-01-13 23:22:47 +00:00
_saveNames [ i ] = " E M P T Y " ;
2008-11-14 21:32:20 +00:00
}
// Get the list of savefiles
2009-01-13 23:22:47 +00:00
SaveStateList list = SaveLoad : : listValidSaves ( ConfMan . getActiveDomainName ( ) ) ;
2008-11-14 21:32:20 +00:00
// Mark the existing savefiles as valid
uint count = 0 ;
2009-01-13 23:22:47 +00:00
SaveStateList : : iterator it = list . begin ( ) ;
while ( it ! = list . end ( ) ) {
2011-07-02 20:25:32 +02:00
int8 slot = it - > getSaveSlot ( ) ;
2009-01-13 23:22:47 +00:00
if ( SaveLoad : : isSlotValid ( slot ) ) {
2018-10-05 23:28:22 +02:00
debugC ( 2 , kDebugScript , " Groovie::Script: Found valid savegame: %s " , it - > getDescription ( ) . encode ( ) . c_str ( ) ) ;
2009-01-13 23:22:47 +00:00
// Mark this slot as used
2022-01-04 20:25:00 -06:00
if ( slot < maxSaves ) {
setVariable ( slot , 1 ) ;
count + + ;
}
2009-01-13 23:22:47 +00:00
// Cache this slot's description
2011-07-02 20:25:32 +02:00
_saveNames [ slot ] = it - > getDescription ( ) ;
2008-11-14 21:32:20 +00:00
}
it + + ;
}
// Save the number of valid saves
2008-11-16 19:20:30 +00:00
setVariable ( 0x104 , count ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: Found %d valid savegames " , count ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_resetvars ( ) {
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " RESETVARS " ) ;
2008-11-14 21:32:20 +00:00
for ( int i = 0 ; i < 0x100 ; i + + ) {
2008-11-16 19:20:30 +00:00
setVariable ( i , 0 ) ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_mod ( ) {
uint16 varnum = readScript8or16bits ( ) ;
uint8 val = readScript8bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: MOD var[0x%04X] %%= %d " , varnum , val ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum , _variables [ varnum ] % val ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_loadscript ( ) {
Common : : String filename ;
char c ;
while ( ( c = readScript8bits ( ) ) ) {
filename + = c ;
}
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: LOADSCRIPT %s " , filename . c_str ( ) ) ;
2008-11-14 21:32:20 +00:00
// Just 1 level of sub-scripts are allowed
if ( _savedCode ) {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Tried to load a level 2 sub-script " ) ;
2008-11-14 21:32:20 +00:00
}
// Save the current code
_savedCode = _code ;
2008-12-24 15:30:31 +00:00
_savedCodeSize = _codeSize ;
2008-11-14 21:32:20 +00:00
_savedInstruction = _currentInstruction ;
// Save the filename of the current script
_savedScriptFile = _scriptFile ;
// Load the sub-script
if ( ! loadScript ( filename ) ) {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Couldn't load sub-script %s " , filename . c_str ( ) ) ;
2008-11-14 21:32:20 +00:00
}
// Save the current stack top
_savedStacktop = _stacktop ;
// Save the variables
memcpy ( _savedVariables , _variables + 0x107 , 0x180 ) ;
}
void Script : : o_setvideoorigin ( ) {
// Read the two offset arguments
int16 origX = readScript16bits ( ) ;
int16 origY = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2008-11-14 21:32:20 +00:00
// Set bitflag 7
_bitflags | = 1 < < 7 ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SetVideoOrigin(0x%04X,0x%04X) (%d, %d) " , origX , origY , origX , origY ) ;
2008-11-14 21:32:20 +00:00
_vm - > _videoPlayer - > setOrigin ( origX , origY ) ;
}
void Script : : o_sub ( ) {
uint16 varnum1 = readScript8or16bits ( ) ;
uint16 varnum2 = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SUB var[0x%04X] -= var[0x%04X] " , varnum1 , varnum2 ) ;
2008-11-14 21:32:20 +00:00
2008-11-16 19:20:30 +00:00
setVariable ( varnum1 , _variables [ varnum1 ] - _variables [ varnum2 ] ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_returnscript ( ) {
uint8 val = readScript8bits ( ) ;
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: RETURNSCRIPT @0x%02X %s @ 0x%04X " , val , _savedScriptFile . c_str ( ) , _savedInstruction ) ;
2008-11-14 21:32:20 +00:00
// Are we returning from a sub-script?
if ( ! _savedCode ) {
2018-10-05 23:28:22 +02:00
error ( " Groovie::Script: Tried to return from the main script " ) ;
2008-11-14 21:32:20 +00:00
}
// Set the return value
2008-11-16 19:20:30 +00:00
setVariable ( 0x102 , val ) ;
2008-11-14 21:32:20 +00:00
// Restore the code
delete [ ] _code ;
_code = _savedCode ;
2008-12-24 15:30:31 +00:00
_codeSize = _savedCodeSize ;
2021-11-13 23:40:27 +02:00
_savedCode = nullptr ;
2008-11-14 21:32:20 +00:00
_currentInstruction = _savedInstruction ;
// Restore the stack
_stacktop = _savedStacktop ;
// Restore the variables
memcpy ( _variables + 0x107 , _savedVariables , 0x180 ) ;
// Restore the filename of the script
_scriptFile = _savedScriptFile ;
2009-09-08 06:23:50 +00:00
_vm - > _videoPlayer - > resetFlags ( ) ;
2008-11-14 21:32:20 +00:00
_vm - > _videoPlayer - > setOrigin ( 0 , 0 ) ;
2021-12-30 22:22:27 -06:00
if ( canDirectSave ( ) ) {
_vm - > saveAutosaveIfEnabled ( ) ;
}
2008-11-14 21:32:20 +00:00
}
void Script : : o_sethotspotright ( ) {
uint16 address = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SETHOTSPOTRIGHT @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_hotspotRightAction = address ;
}
void Script : : o_sethotspotleft ( ) {
uint16 address = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SETHOTSPOTLEFT @0x%04X " , address ) ;
2008-11-14 21:32:20 +00:00
_hotspotLeftAction = address ;
}
void Script : : o_getcd ( ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: GETCD " ) ;
2008-11-14 21:32:20 +00:00
// By default set it to no CD available
int8 cd = - 1 ;
// Try to open one file from each CD
Common : : File cdfile ;
if ( cdfile . open ( " b.gjd " ) ) {
cdfile . close ( ) ;
cd = 1 ;
}
if ( cdfile . open ( " at.gjd " ) ) {
cdfile . close ( ) ;
if ( cd = = 1 ) {
// Both CDs are available
cd = 0 ;
} else {
cd = 2 ;
}
}
2008-11-16 19:20:30 +00:00
setVariable ( 0x106 , cd ) ;
2008-11-14 21:32:20 +00:00
}
2008-11-25 00:41:51 +00:00
void Script : : o_playcd ( ) {
2008-11-14 21:32:20 +00:00
uint8 val = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: PLAYCD %d " , val ) ;
2008-11-14 21:32:20 +00:00
if ( val = = 2 ) {
2008-11-25 00:41:51 +00:00
// TODO: Play the alternative logo
2008-11-14 21:32:20 +00:00
}
2008-11-25 00:41:51 +00:00
_vm - > _musicPlayer - > playCD ( val ) ;
2008-11-14 21:32:20 +00:00
}
2009-08-05 13:57:40 +00:00
void Script : : o_musicdelay ( ) {
uint16 delay = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: MUSICDELAY %d " , delay ) ;
2009-08-05 13:57:40 +00:00
_vm - > _musicPlayer - > setBackgroundDelay ( delay ) ;
}
2008-11-14 21:32:20 +00:00
void Script : : o_hotspot_outrect ( ) {
uint16 left = readScript16bits ( ) ;
uint16 top = readScript16bits ( ) ;
uint16 right = readScript16bits ( ) ;
uint16 bottom = readScript16bits ( ) ;
uint16 address = readScript16bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: HOTSPOT-OUTRECT(%d,%d,%d,%d) @0x%04X (TODO) " , left , top , right , bottom , address ) ;
2008-11-14 21:32:20 +00:00
// Test if the current mouse position is outside the specified rectangle
Common : : Rect rect ( left , top , right , bottom ) ;
Common : : Point mousepos = _vm - > _system - > getEventManager ( ) - > getMousePos ( ) ;
bool contained = rect . contains ( mousepos ) ;
if ( ! contained ) {
2014-11-03 01:08:15 +02:00
_currentInstruction = address ;
2008-11-14 21:32:20 +00:00
}
}
void Script : : o_stub56 ( ) {
uint32 val1 = readScript32bits ( ) ;
uint8 val2 = readScript8bits ( ) ;
uint8 val3 = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: STUB56: 0x%08X 0x%02X 0x%02X " , val1 , val2 , val3 ) ;
2008-11-14 21:32:20 +00:00
}
void Script : : o_stub59 ( ) {
uint16 val1 = readScript8or16bits ( ) ;
uint8 val2 = readScript8bits ( ) ;
2009-01-01 15:06:43 +00:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: STUB59: 0x%04X 0x%02X " , val1 , val2 ) ;
2008-11-14 21:32:20 +00:00
}
2018-01-13 22:53:24 +01:00
void Script : : o2_printstring ( ) {
uint16 posx = readScript16bits ( ) ;
uint16 posy = readScript16bits ( ) ;
uint8 colr = readScript8bits ( ) ;
uint8 colg = readScript8bits ( ) ;
uint8 colb = readScript8bits ( ) ;
uint32 col = _vm - > _pixelFormat . RGBToColor ( colr , colg , colb ) ;
2018-10-05 23:28:22 +02:00
Common : : String text ;
2018-01-13 22:53:24 +01:00
2018-10-05 23:28:22 +02:00
// Read string from Script
readScriptString ( text ) ;
debugC ( 1 , kDebugScript , " Groovie::Script: PRINTSTRING (%d, %d): %s " , posx , posy , text . c_str ( ) ) ;
2018-01-13 22:53:24 +01:00
2022-01-02 23:21:53 -06:00
_vm - > _videoPlayer - > drawString ( text , posx , posy , col ) ;
2018-01-13 22:53:24 +01:00
}
2009-08-21 13:57:03 +00:00
void Script : : o2_playsong ( ) {
2009-03-10 21:54:45 +00:00
uint32 fileref = readScript32bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: PlaySong(0x%08X): Play xmidi file " , fileref ) ;
2009-03-10 21:54:45 +00:00
_vm - > _musicPlayer - > playSong ( fileref ) ;
}
2018-10-05 23:28:22 +02:00
void Script : : o2_midicontrol ( ) {
uint16 arg1 = readScript16bits ( ) ;
uint16 arg2 = readScript16bits ( ) ;
switch ( arg1 ) {
case 0 :
// Stop Playback
debugC ( 1 , kDebugScript , " Groovie::Script: MIDI %d:Stop: %d " , arg1 , arg2 ) ;
2021-09-08 19:09:01 -05:00
_vm - > _musicPlayer - > stop ( ) ;
_vm - > _soundQueue . stopAll ( ) ;
2018-10-05 23:28:22 +02:00
break ;
case 1 :
// Play song from index
debugC ( 1 , kDebugScript , " Groovie::Script: MIDI %d: Play song %d " , arg1 , arg2 ) ;
_vm - > _musicPlayer - > playSong ( arg2 ) ;
break ;
case 3 :
2021-08-27 00:41:07 -05:00
// TODO: Set Volume? Or is it some kind of fade in / out
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: MIDI %d: Set volume/time: %d " , arg1 , arg2 ) ;
2021-11-06 20:07:57 +01:00
//_vm->_musicPlayer->setGameVolume(arg2, 0);
2018-10-05 23:28:22 +02:00
break ;
}
}
2009-08-21 13:57:03 +00:00
void Script : : o2_setbackgroundsong ( ) {
2009-03-10 21:54:45 +00:00
uint32 fileref = readScript32bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SetBackgroundSong(0x%08X) " , fileref ) ;
2009-03-10 21:54:45 +00:00
_vm - > _musicPlayer - > setBackgroundSong ( fileref ) ;
}
2009-08-21 13:57:03 +00:00
void Script : : o2_videofromref ( ) {
2009-03-10 21:54:45 +00:00
uint32 fileref = readScript32bits ( ) ;
2022-01-09 15:51:34 -06:00
// the fileref differs between languages, but the instruction pointers and script sizes are the same
2021-10-26 03:54:05 +03:00
// Skip the 11th Hour intro videos on right mouse click, instead of
// fast-forwarding them. This has the same effect as pressing 'p' twice in
// the skulls screen after the Groovie logo
2022-01-09 15:51:34 -06:00
if ( _version = = kGroovieT11H & & _currentInstruction = = 0x0560 & & fileref ! = _videoRef )
2021-10-26 03:54:05 +03:00
_videoSkipAddress = 1417 ;
2022-01-09 15:51:34 -06:00
if ( _version = = kGroovieT11H & & fileref ! = _videoRef & & ! ConfMan . getBool ( " originalsaveload " ) ) {
2021-12-04 03:00:10 +02:00
if ( _currentInstruction = = 0xE50A ) {
// Load from the main menu
GUI : : SaveLoadChooser * dialog = new GUI : : SaveLoadChooser ( _ ( " Restore game: " ) , _ ( " Restore " ) , false ) ;
int slot = dialog - > runModalWithCurrentTarget ( ) ;
delete dialog ;
if ( slot > = 0 ) {
_currentInstruction = 0xE790 ;
loadgame ( slot ) ;
return ;
} else {
_currentInstruction = 0xBF37 ; // main menu
}
} else if ( _currentInstruction = = 0xE955 ) {
// Save from the main menu
GUI : : SaveLoadChooser * dialog = new GUI : : SaveLoadChooser ( _ ( " Save game: " ) , _ ( " Save " ) , true ) ;
int slot = dialog - > runModalWithCurrentTarget ( ) ;
Common : : String saveName = dialog - > getResultString ( ) ;
delete dialog ;
if ( slot > = 0 ) {
directGameSave ( slot , saveName ) ;
}
_currentInstruction = 0xBF37 ; // main menu
}
}
2009-03-10 21:54:45 +00:00
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: VIDEOFROMREF(0x%08X) (Not fully imp): Play video file from ref " , fileref ) ;
2021-12-09 11:42:03 -06:00
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d via 0x09 (o2_videofromref) " , _currentInstruction - 5 , fileref ) ;
2009-03-10 21:54:45 +00:00
}
2009-08-21 13:57:03 +00:00
2018-10-05 23:28:22 +02:00
// Clear bit 1
_bitflags & = ~ ( 1 < < 1 ) ;
2009-03-10 21:54:45 +00:00
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction - = 5 ;
}
}
2009-08-21 13:57:03 +00:00
void Script : : o2_vdxtransition ( ) {
2009-03-10 21:54:45 +00:00
uint32 fileref = readScript32bits ( ) ;
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: VDX transition fileref = 0x%08X " , fileref ) ;
2021-12-09 11:42:03 -06:00
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing video %d with transition via 0x1C (o2_vdxtransition) " , _currentInstruction - 5 , fileref ) ;
2009-03-10 21:54:45 +00:00
}
// Set bit 1
_bitflags | = 1 < < 1 ;
// Set bit 2 if _firstbit
if ( _firstbit ) {
_bitflags | = 1 < < 2 ;
}
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction - = 5 ;
}
}
2018-12-27 23:15:02 +01:00
void Script : : o2_savescreen ( ) {
2009-12-24 08:35:11 +00:00
uint16 val = readScript16bits ( ) ;
2021-09-14 01:01:29 -05:00
// TODO: Parameter
2014-11-03 11:33:33 +02:00
if ( val )
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: o2_copyscreentobg: Param is %d " , val ) ;
2016-10-09 14:59:58 +02:00
2018-12-27 23:15:02 +01:00
_vm - > _graphicsMan - > saveScreen ( ) ;
2014-11-03 11:33:33 +02:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: CopyScreenToBG3: 0x%04X " , val ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: CopyScreenToBG3: 0x%04X " , _currentInstruction - 3 , val ) ;
2009-12-24 08:35:11 +00:00
}
2018-12-27 23:15:02 +01:00
void Script : : o2_restorescreen ( ) {
2009-12-24 08:35:11 +00:00
uint16 val = readScript16bits ( ) ;
2021-09-14 01:01:29 -05:00
// TODO: Parameter
2014-11-03 11:33:33 +02:00
if ( val )
2018-10-05 23:28:22 +02:00
warning ( " Groovie::Script: o2_copybgtoscreen: Param is %d " , val ) ;
2014-11-03 11:33:33 +02:00
2018-12-27 23:15:02 +01:00
_vm - > _graphicsMan - > restoreScreen ( ) ;
2014-11-03 11:33:33 +02:00
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: CopyBG3ToScreen: 0x%04X " , val ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: CopyBG3ToScreen: 0x%04X " , _currentInstruction - 3 , val ) ;
2009-12-24 08:35:11 +00:00
}
2009-08-21 13:57:03 +00:00
void Script : : o2_setvideoskip ( ) {
_videoSkipAddress = readScript16bits ( ) ;
2018-10-05 23:28:22 +02:00
debugC ( 1 , kDebugScript , " Groovie::Script: SetVideoSkip (0x%04X) " , _videoSkipAddress ) ;
2009-08-21 13:57:03 +00:00
}
2021-10-23 02:42:39 +03:00
// This function depends on the actual game played. There was an initial version
// for T7G, and then it kept being expanded in newer games (11H, Clan, UHP). This
// means that newer games contained logic used in older ones (e.g. Clandestiny
// and UHP include the hardcoded puzzle logic of 11H).
2021-09-16 09:23:34 +03:00
void Script : : o_gamelogic ( ) {
uint8 param = readScript8bits ( ) ;
2021-10-23 04:06:47 +03:00
debugC ( 1 , kDebugScript , " Groovie::Script: Mini game logic, param %d " , param ) ;
2018-01-13 23:50:30 +01:00
switch ( _version ) {
2021-09-16 09:23:34 +03:00
case kGroovieT7G :
if ( ! _cellGame )
2021-12-04 08:04:35 -06:00
_cellGame = new CellGame ( ConfMan . getBool ( " easier_ai " ) ) ;
2018-01-13 23:50:30 +01:00
2021-10-23 20:19:32 +03:00
_cellGame - > run ( param , & _variables [ 0x19 ] ) ;
2018-01-13 23:50:30 +01:00
2021-09-16 09:23:34 +03:00
// Set the movement origin
setVariable ( 0 , _cellGame - > getStartY ( ) ) ; // y
setVariable ( 1 , _cellGame - > getStartX ( ) ) ; // x
// Set the movement destination
setVariable ( 2 , _cellGame - > getEndY ( ) ) ;
setVariable ( 3 , _cellGame - > getEndX ( ) ) ;
2018-01-13 23:50:30 +01:00
break ;
2021-09-16 09:23:34 +03:00
# ifdef ENABLE_GROOVIE2
case kGroovieT11H :
2021-10-22 01:12:39 +03:00
case kGroovieCDY :
2021-10-23 02:42:39 +03:00
case kGroovieUHP :
switch ( param ) {
2021-10-23 04:06:47 +03:00
case 1 : // 11H Cake puzzle in the dining room (tb.grv)
2021-10-23 02:42:39 +03:00
_cake . run ( _variables ) ;
break ;
2021-10-23 04:06:47 +03:00
case 2 : // 11H/UHP Beehive puzzle in the top room (hs.grv)
2021-10-23 02:42:39 +03:00
_beehive . run ( _variables ) ;
break ;
2021-10-23 04:06:47 +03:00
case 3 : // 11H Gallery puzzle in the modern art painting (bs.grv)
2021-10-23 02:42:39 +03:00
_gallery . run ( _variables ) ;
break ;
2021-10-23 04:06:47 +03:00
case 4 : // 11H Triangle puzzle in the chapel (tx.grv)
2021-10-23 19:54:16 +03:00
_triangle . run ( _variables ) ;
2021-10-23 02:42:39 +03:00
break ;
2021-10-23 04:06:47 +03:00
case 5 : // 11H/UHP Mouse trap puzzle in the lab (al.grv)
2021-10-23 02:42:39 +03:00
_mouseTrap . run ( _variables ) ;
break ;
2021-10-23 04:06:47 +03:00
case 6 : // 11H Pente puzzle at the end of the game (pt.grv)
2021-10-23 20:19:32 +03:00
_pente . run ( _variables ) ;
2021-10-23 02:42:39 +03:00
break ;
2021-10-28 13:45:27 +03:00
case 7 : // Clan Wine rack puzzle
_wineRack . run ( _variables ) ;
2021-10-23 02:42:39 +03:00
break ;
2021-10-23 04:06:47 +03:00
case 8 : // Clan/UHP Othello/Reversi puzzle
2021-10-23 20:19:32 +03:00
_othello . run ( _variables ) ;
2021-10-23 02:42:39 +03:00
break ;
default :
debugC ( 1 , kDebugScript , " Groovie::Script: Op42 (0x%02X): Invalid -> NOP " , param ) ;
}
2021-10-22 01:12:39 +03:00
break ;
2021-10-23 02:42:39 +03:00
case kGroovieTLC :
if ( ! _tlcGame )
_tlcGame = new TlcGame ( _variables ) ;
2021-10-22 01:12:39 +03:00
2021-10-23 02:42:39 +03:00
_tlcGame - > handleOp ( param ) ;
2021-10-22 01:12:39 +03:00
break ;
2021-09-12 22:43:42 -05:00
# endif
2021-10-22 01:12:39 +03:00
2018-01-13 23:50:30 +01:00
default :
2021-10-23 20:19:32 +03:00
warning ( " Groovie::Script: OpCode 0x42 (param %d) for current game is not implemented yet. " , param ) ;
break ;
2018-01-13 23:50:30 +01:00
}
2014-11-03 11:36:25 +02:00
}
2021-09-01 19:34:53 -05:00
void Script : : o2_copyfgtobg ( ) {
2009-03-10 21:54:45 +00:00
uint8 arg = readScript8bits ( ) ;
2021-09-01 19:34:53 -05:00
debugC ( 1 , kDebugScript , " Groovie::Script: o2_copyfgtobg (0x%02X) " , arg ) ;
debugC ( 2 , kDebugVideo , " Groovie::Script: @0x%04X: o2_copyfgtobg (0x%02X) " , _currentInstruction - 2 , arg ) ;
2022-01-04 01:19:58 -06:00
_vm - > _videoPlayer - > copyfgtobg ( arg ) ;
2009-03-10 21:54:45 +00:00
}
2009-08-21 13:57:03 +00:00
void Script : : o2_setscriptend ( ) {
uint16 arg = readScript16bits ( ) ;
2022-01-04 20:25:00 -06:00
debugC ( 0 , kDebugScript , " Groovie::Script: SetScriptEnd (0x%04X) " , arg ) ;
// TODO: seems to write arg as a uint32 to var 0x38 to 0x3B?
2009-08-21 13:57:03 +00:00
}
2021-09-01 19:34:53 -05:00
void Script : : o2_playsound ( ) {
uint32 fileref = readScript32bits ( ) ;
uint8 loops = readScript8bits ( ) ; // 0 means loop forever, 1 means play once
uint8 val3 = readScript8bits ( ) ;
debugC ( 1 , kDebugScript , " Groovie::Script: o2_playsound: 0x%08X 0x%02X 0x%02X " , fileref , loops , val3 ) ;
if ( fileref = = 0 & & loops = = 0 ) {
_vm - > _soundQueue . stopAll ( ) ;
return ;
}
playBackgroundSound ( fileref , loops ) ;
}
2021-10-27 19:09:49 -05:00
void Script : : o_wipemaskfromstring58 ( ) {
// used in pente when pieces are captured
Common : : String vidName ;
uint16 instStart = _currentInstruction ;
uint32 fileref = getVideoRefString ( vidName ) ;
setBitFlag ( 10 , true ) ;
// Show the debug information just when starting the playback
if ( fileref ! = _videoRef ) {
debugC ( 0 , kDebugScript , " Groovie::Script: WIPEMASKFROMSTRING58 %d ('%s') " , fileref , vidName . c_str ( ) ) ;
debugC ( 2 , kDebugVideo , " \n Groovie::Script: @0x%04X: Playing mask video %d ('%s') via 0x58 (o_wipemaskfromstring58) " , instStart - 1 , fileref , vidName . c_str ( ) ) ;
}
// Play the video
if ( ! playvideofromref ( fileref ) ) {
// Move _currentInstruction back
_currentInstruction = instStart - 1 ;
}
}
2021-09-01 19:34:53 -05:00
void Script : : o2_check_sounds_overlays ( ) {
2021-08-29 16:33:00 -05:00
uint16 val1 = readScript8or16bits ( ) ;
uint8 val2 = readScript8bits ( ) ;
debugC ( 1 , kDebugScript , " Groovie::Script: STUB59: 0x%04X 0x%02X " , val1 , val2 ) ;
2021-09-01 19:34:53 -05:00
// bitflag 0 is set by background sounds (clock chimes, wind, heart, drip in the kitchen)
// bitflag 2 is set by overlay videos
// this instruction is notably used at the end of the game when you have until midnight to choose a door
_variables [ val1 ] = getBitFlag ( 0 ) | | getBitFlag ( 2 ) ;
2021-08-29 16:33:00 -05:00
}
2021-09-15 22:50:44 -05:00
void Script : : o2_preview_loadgame ( ) {
uint8 save_slot = readScript8bits ( ) ;
if ( preview_loadgame ( save_slot ) )
return ;
for ( int i = 0 ; i < 15 ; i + + ) {
_variables [ i ] = 0xf0 ;
}
for ( int i = 15 ; i < 22 ; i + + ) {
_variables [ i ] = 0x4a ;
}
}
2009-03-10 00:19:44 +00:00
Script : : OpcodeFunc Script : : _opcodesT7G [ NUM_OPCODES ] = {
2008-11-14 21:32:20 +00:00
& Script : : o_nop , // 0x00
2009-01-01 15:06:43 +00:00
& Script : : o_nop ,
2008-11-14 21:32:20 +00:00
& Script : : o_playsong ,
& Script : : o_bf9on ,
& Script : : o_palfadeout , // 0x04
& Script : : o_bf8on ,
& Script : : o_bf6on ,
& Script : : o_bf7on ,
& Script : : o_setbackgroundsong , // 0x08
& Script : : o_videofromref ,
& Script : : o_bf5on ,
& Script : : o_inputloopstart ,
& Script : : o_keyboardaction , // 0x0C
& Script : : o_hotspot_rect ,
& Script : : o_hotspot_left ,
& Script : : o_hotspot_right ,
& Script : : o_hotspot_center , // 0x10
& Script : : o_hotspot_center ,
& Script : : o_hotspot_current ,
& Script : : o_inputloopend ,
& Script : : o_random , // 0x14
& Script : : o_jmp ,
& Script : : o_loadstring ,
& Script : : o_ret ,
& Script : : o_call , // 0x18
& Script : : o_sleep ,
& Script : : o_strcmpnejmp ,
& Script : : o_xor_obfuscate ,
& Script : : o_vdxtransition , // 0x1C
& Script : : o_swap ,
& Script : : o_nop8 ,
& Script : : o_inc ,
& Script : : o_dec , // 0x20
& Script : : o_strcmpnejmp_var ,
& Script : : o_copybgtofg ,
& Script : : o_strcmpeqjmp ,
& Script : : o_mov , // 0x24
& Script : : o_add ,
& Script : : o_videofromstring1 , // Reads a string and then does stuff: used by book in library
& Script : : o_videofromstring2 , // play vdx file from string, after setting 1 (and 2 if firstbit)
& Script : : o_nop16 , // 0x28
& Script : : o_stopmidi ,
& Script : : o_endscript ,
& Script : : o_nop ,
& Script : : o_sethotspottop , // 0x2C
& Script : : o_sethotspotbottom ,
& Script : : o_loadgame ,
& Script : : o_savegame ,
& Script : : o_hotspotbottom_4 , // 0x30
& Script : : o_midivolume ,
& Script : : o_jne ,
& Script : : o_loadstringvar ,
& Script : : o_chargreatjmp , // 0x34
& Script : : o_bf7off ,
& Script : : o_charlessjmp ,
& Script : : o_copyrecttobg ,
& Script : : o_restorestkpnt , // 0x38
& Script : : o_obscureswap ,
2021-08-26 18:01:39 -05:00
& Script : : o_printstring ,
2008-11-14 21:32:20 +00:00
& Script : : o_hotspot_slot ,
& Script : : o_checkvalidsaves , // 0x3C
& Script : : o_resetvars ,
& Script : : o_mod ,
& Script : : o_loadscript ,
& Script : : o_setvideoorigin , // 0x40
& Script : : o_sub ,
2021-09-16 09:23:34 +03:00
& Script : : o_gamelogic ,
2008-11-14 21:32:20 +00:00
& Script : : o_returnscript ,
& Script : : o_sethotspotright , // 0x44
& Script : : o_sethotspotleft ,
& Script : : o_nop ,
& Script : : o_nop ,
& Script : : o_nop8 , // 0x48
& Script : : o_nop ,
& Script : : o_nop16 ,
& Script : : o_nop8 ,
& Script : : o_getcd , // 0x4C
2008-11-25 00:41:51 +00:00
& Script : : o_playcd ,
2009-08-05 13:57:40 +00:00
& Script : : o_musicdelay ,
2008-11-14 21:32:20 +00:00
& Script : : o_nop16 ,
& Script : : o_nop16 , // 0x50
& Script : : o_nop16 ,
//&Script::o_nop8,
& Script : : o_invalid , // Do loads with game area, maybe draw dirty areas?
& Script : : o_hotspot_outrect ,
& Script : : o_nop , // 0x54
& Script : : o_nop16 ,
& Script : : o_stub56 ,
//&Script::o_nop32,
& Script : : o_invalid , // completely unimplemented, plays vdx in some way
//&Script::o_nop, // 0x58
& Script : : o_invalid , // 0x58 // like above, but plays from string not ref
2021-09-15 22:50:44 -05:00
& Script : : o_stub59 ,
& Script : : o_invalid
2008-11-14 21:32:20 +00:00
} ;
2009-03-10 00:19:44 +00:00
Script : : OpcodeFunc Script : : _opcodesV2 [ NUM_OPCODES ] = {
2009-03-10 21:54:45 +00:00
& Script : : o_invalid , // 0x00
2009-03-10 00:19:44 +00:00
& Script : : o_nop ,
2009-03-10 21:54:45 +00:00
& Script : : o2_playsong ,
2009-08-21 13:57:03 +00:00
& Script : : o_nop ,
& Script : : o_nop , // 0x04
& Script : : o_nop ,
& Script : : o_nop ,
& Script : : o_nop ,
2009-03-10 21:54:45 +00:00
& Script : : o2_setbackgroundsong , // 0x08
& Script : : o2_videofromref ,
2021-09-08 18:51:26 -05:00
& Script : : o2_bf0on ,
2009-03-10 00:19:44 +00:00
& Script : : o_inputloopstart ,
& Script : : o_keyboardaction , // 0x0C
& Script : : o_hotspot_rect ,
& Script : : o_hotspot_left ,
& Script : : o_hotspot_right ,
& Script : : o_hotspot_center , // 0x10
& Script : : o_hotspot_center ,
& Script : : o_hotspot_current ,
& Script : : o_inputloopend ,
& Script : : o_random , // 0x14
& Script : : o_jmp ,
& Script : : o_loadstring ,
& Script : : o_ret ,
& Script : : o_call , // 0x18
& Script : : o_sleep ,
& Script : : o_strcmpnejmp ,
& Script : : o_xor_obfuscate ,
2009-03-10 21:54:45 +00:00
& Script : : o2_vdxtransition , // 0x1C
2009-03-10 00:19:44 +00:00
& Script : : o_swap ,
2009-08-21 13:57:03 +00:00
& Script : : o_invalid ,
2009-03-10 00:19:44 +00:00
& Script : : o_inc ,
& Script : : o_dec , // 0x20
& Script : : o_strcmpnejmp_var ,
2021-08-26 20:58:10 -05:00
& Script : : o2_copybgtofg ,
2009-03-10 00:19:44 +00:00
& Script : : o_strcmpeqjmp ,
& Script : : o_mov , // 0x24
& Script : : o_add ,
& Script : : o_videofromstring1 ,
& Script : : o_videofromstring2 ,
2009-08-21 13:57:03 +00:00
& Script : : o_invalid , // 0x28
2009-03-10 00:19:44 +00:00
& Script : : o_nop ,
2009-08-21 13:57:03 +00:00
& Script : : o_endscript ,
& Script : : o_invalid ,
2009-03-10 00:19:44 +00:00
& Script : : o_sethotspottop , // 0x2C
& Script : : o_sethotspotbottom ,
& Script : : o_loadgame ,
& Script : : o_savegame ,
& Script : : o_hotspotbottom_4 , // 0x30
2018-10-05 23:28:22 +02:00
& Script : : o2_midicontrol ,
2009-03-10 00:19:44 +00:00
& Script : : o_jne ,
& Script : : o_loadstringvar ,
& Script : : o_chargreatjmp , // 0x34
& Script : : o_bf7off ,
& Script : : o_charlessjmp ,
& Script : : o_copyrecttobg ,
& Script : : o_restorestkpnt , // 0x38
& Script : : o_obscureswap ,
2021-08-27 13:38:26 -05:00
& Script : : o2_printstring ,
2009-03-10 00:19:44 +00:00
& Script : : o_hotspot_slot ,
& Script : : o_checkvalidsaves , // 0x3C
& Script : : o_resetvars ,
& Script : : o_mod ,
& Script : : o_loadscript ,
& Script : : o_setvideoorigin , // 0x40
& Script : : o_sub ,
2021-09-16 09:23:34 +03:00
& Script : : o_gamelogic ,
2009-03-10 00:19:44 +00:00
& Script : : o_returnscript ,
& Script : : o_sethotspotright , // 0x44
& Script : : o_sethotspotleft ,
2009-08-21 13:57:03 +00:00
& Script : : o_invalid ,
& Script : : o_invalid ,
& Script : : o_invalid , // 0x48
& Script : : o_invalid ,
2009-03-10 00:19:44 +00:00
& Script : : o_nop16 ,
2009-08-21 13:57:03 +00:00
& Script : : o_invalid ,
& Script : : o_invalid , // 0x4C
& Script : : o_invalid ,
& Script : : o_invalid ,
2018-12-27 23:15:02 +01:00
& Script : : o2_savescreen ,
& Script : : o2_restorescreen , // 0x50
2009-08-21 13:57:03 +00:00
& Script : : o2_setvideoskip ,
2021-09-01 19:34:53 -05:00
& Script : : o2_copyfgtobg ,
2009-03-10 00:19:44 +00:00
& Script : : o_hotspot_outrect ,
2009-08-21 13:57:03 +00:00
& Script : : o_invalid , // 0x54
& Script : : o2_setscriptend ,
2021-09-01 19:34:53 -05:00
& Script : : o2_playsound ,
2009-03-10 00:19:44 +00:00
& Script : : o_invalid ,
2021-10-27 19:09:49 -05:00
& Script : : o_wipemaskfromstring58 , // 0x58
2021-09-15 22:50:44 -05:00
& Script : : o2_check_sounds_overlays ,
& Script : : o2_preview_loadgame
2009-03-10 00:19:44 +00:00
} ;
2008-11-14 21:32:20 +00:00
} // End of Groovie namespace