diff options
| author | Vicent Marti | 2008-09-20 11:21:35 +0000 |
|---|---|---|
| committer | Vicent Marti | 2008-09-20 11:21:35 +0000 |
| commit | 9feb0f5f6710970fb64e525622d22a5aca18de92 (patch) | |
| tree | 620d6c7b94be463bd71c7419e41c7e8d120305d4 /engines | |
| parent | c7e07102b69a5fd66a89605c619e008060744bf4 (diff) | |
| parent | 221b4a47aea63bdf05b17def32f2a722f230d433 (diff) | |
| download | scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.tar.gz scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.tar.bz2 scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.zip | |
- Merged the new RTL changes into the branch.
- Fixed conflicts.
- Added new RTL dialogs to the Theme Description files.
Full SVNMerge log:
==================
Merged revisions 33928,33930,33932-33936,33938-33940,33942-33943,33948,33950,33953,33967,33973,33976,33978,33980,33985,33991,33993,33999-34000,34006,34009,34011,34013,34015,34019,34021-34023,34025,34027-34028,34030,34032-34034,34036,34038-34039,34041,34046-34048,34050-34055,34057,34059-34065,34067,34072,34074,34076,34078-34081,34084,34086-34087,34089-34090,34093,34096-34102,34104,34107,34113,34116,34119,34122,34124,34126,34128,34131-34132,34135,34138,34141,34144,34146,34149,34152-34154,34156-34157,34160,34163-34164,34169,34173,34179-34194,34196-34198,34200-34201,34205-34206,34208-34217,34219-34225,34227-34228,34234-34237,34239-34249,34251-34279,34281-34284,34286-34288,34290-34320,34323-34324,34326,34328-34329,34332,34334,34336,34338-34340,34343-34353,34356-34357,34359-34371,34373,34375,34378,34381-34382,34384-34385,34389-34391,34393-34394,34396-34397,34399-34405,34407-34409,34411,34413,34415,34417-34420,34423-34426,34428-34438,34440-34454,34456-34458,34460,34462-34469,34472,34474,34479-34481,34483-34498,34501-34505,34508,34511-34518,34520-34524,34526-34563,34566-34569,34571-34590,34592,34595-34599,34602-34603 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
........
r33928 | peres001 | 2008-08-16 08:39:58 +0200 (Sat, 16 Aug 2008) | 1 line
Fixed label positioning in BRA.
........
r33930 | peres001 | 2008-08-16 09:47:44 +0200 (Sat, 16 Aug 2008) | 1 line
Enabled interaction with movable zones - mainly NPCs - which are linked to animations.
........
r33932 | anotherguest | 2008-08-16 10:49:36 +0200 (Sat, 16 Aug 2008) | 1 line
Enable CINE
........
r33933 | peres001 | 2008-08-16 10:57:07 +0200 (Sat, 16 Aug 2008) | 1 line
Fixed half-invisible balloons.
........
r33934 | fingolfin | 2008-08-16 13:37:36 +0200 (Sat, 16 Aug 2008) | 1 line
Replaced ARM_USE_GFX_ASM by USE_ARM_GFX_ASM
........
r33935 | buddha_ | 2008-08-16 13:38:43 +0200 (Sat, 16 Aug 2008) | 1 line
Changed AdlibRegisterSoundInstrument's member variables from unsigned 16-bit to unsigned 8-bit. Maybe this'll fix the crash in AdlibSoundDriver::setupInstrument() eriktorbjorn was getting in Future Wars when teleporting from the photocopier room to the swamp. There was a OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease) call with sustainRelease = 65452. Now there shouldn't be any such calls made because the sustainRelease value is always 8-bit now. Hopefully this won't break anything.
........
r33936 | eriktorbjorn | 2008-08-16 13:50:36 +0200 (Sat, 16 Aug 2008) | 2 lines
Removed unused variable.
........
r33938 | athrxx | 2008-08-16 14:38:37 +0200 (Sat, 16 Aug 2008) | 4 lines
- KYRA: FM-Towns/PC-98 Audio: fixed several bugs and got rid of some floating point arithmetic (or at least replaced some doubles with floats)
- Improved support for PC-98 music: HOF tracks seem to be fine, KYRA should be okay, too (I can't compare with an emulator since I am missing the floppy boot disk with the executable)
- There are still tempo issues. Some tracks play way too slow, others way too fast
- PC-98 sound effects in Kyra 1 don't work (I would need the floppy disk with the executable for that)
........
r33939 | peres001 | 2008-08-16 14:49:27 +0200 (Sat, 16 Aug 2008) | 1 line
Multiple balloons (answers) are now positioned correctly in BRA.
........
r33940 | peres001 | 2008-08-16 15:10:54 +0200 (Sat, 16 Aug 2008) | 1 line
Extended balloon manager to handle color constants and fixed color of text in balloons for BRA.
........
r33942 | athrxx | 2008-08-16 16:25:03 +0200 (Sat, 16 Aug 2008) | 1 line
KYRA: Fm-Towns Audio: fixed music fading
........
r33943 | athrxx | 2008-08-16 17:24:52 +0200 (Sat, 16 Aug 2008) | 1 line
KYRA: Fm-Towns Audio: fixed crash
........
r33948 | lordhoto | 2008-08-16 23:51:56 +0200 (Sat, 16 Aug 2008) | 2 lines
Cleanup.
........
r33950 | buddha_ | 2008-08-17 00:15:57 +0200 (Sun, 17 Aug 2008) | 5 lines
Workaround for bug #2054882 (FW: Impossible to survive entering monastery (regression)):
For Future Wars o1_compareGlobalVar now compares global variable 255 to be equal to everything.
The scripts probably tested global variable 255 for equality with some value (Maybe 143?)
to see whether copy protection was properly passed.
........
r33953 | lordhoto | 2008-08-17 00:30:47 +0200 (Sun, 17 Aug 2008) | 2 lines
Properly close files opened when checking for config file on WIN32.
........
r33967 | buddha_ | 2008-08-17 12:43:54 +0200 (Sun, 17 Aug 2008) | 1 line
Forwardport of branch-0-12-0's r33966: Fix to Future Wars's rendering of type 0 overlays (i.e. color sprites). Objects with negative frame values are supposed to be jumped over (Verified with disassembly).
........
r33973 | sev | 2008-08-17 20:58:23 +0200 (Sun, 17 Aug 2008) | 2 lines
Patch #2045543: Possible fix for Drascula's decodeRLE()
........
r33976 | buddha_ | 2008-08-17 22:53:18 +0200 (Sun, 17 Aug 2008) | 1 line
Added some documentation about how data is unpacked in gfxConvertSpriteToRaw (Learned this from trying to implement convertPI1_2 i.e. gfxConvertSpriteToRaw myself to see if that was the problem with the Operation Stealth's labyrinth arcade sequence).
........
r33978 | anotherguest | 2008-08-17 23:16:07 +0200 (Sun, 17 Aug 2008) | 1 line
Improved filehandling for securer and quicker way to get ref to file session
........
r33980 | athrxx | 2008-08-18 00:49:34 +0200 (Mon, 18 Aug 2008) | 4 lines
KYRA: FM-Towns/PC-98 Audio:
- improved accuracy
- complete percussion channel support (does not work atm though, since the instrument data is missing)
- some cleanup
........
r33985 | peres001 | 2008-08-18 09:12:05 +0200 (Mon, 18 Aug 2008) | 3 lines
* Split up blt routine (there is room for a ton of improvements)
* Added scaling as a new blt option
* Activated scaling for the main character in BRA
........
r33991 | knakos | 2008-08-18 19:24:25 +0200 (Mon, 18 Aug 2008) | 1 line
do away with the smush force redraw hack
........
r33993 | athrxx | 2008-08-18 19:42:32 +0200 (Mon, 18 Aug 2008) | 3 lines
KYRA: FM-Towns/PC-98 Audio:
- adpcm decoding for rhythm channel
- cleanup
........
r33999 | knakos | 2008-08-18 20:15:32 +0200 (Mon, 18 Aug 2008) | 1 line
switching to libTremolo
........
r34000 | anotherguest | 2008-08-18 20:16:24 +0200 (Mon, 18 Aug 2008) | 1 line
Do Deinit of pixel buffer when hiding menu.That saves 600KB in VGA games for low memory devices.
........
r34006 | robinwatts | 2008-08-18 22:04:15 +0200 (Mon, 18 Aug 2008) | 8 lines
Updates to the scummvm blitting code as discussed on the mailing list.
1) Remove DS version of the ARM blitters in favour of the 'normal' ARM one.
2) Update normal ARM blitter to use Carlo's clever algorithm.
3) Update C version with Max Horns patch (slightly tweaked - counting down
on loops is better, M'kay).
........
r34009 | tramboi | 2008-08-18 22:43:44 +0200 (Mon, 18 Aug 2008) | 1 line
Compile fix for 34006
........
r34011 | anotherguest | 2008-08-18 23:09:46 +0200 (Mon, 18 Aug 2008) | 1 line
Enable quick F5 save key for Touche!
........
r34013 | anotherguest | 2008-08-18 23:19:18 +0200 (Mon, 18 Aug 2008) | 1 line
Enable save game action key in Touche for WinCE devices.
........
r34015 | athrxx | 2008-08-19 03:00:15 +0200 (Tue, 19 Aug 2008) | 2 lines
fixed bug that caused a lockup in certain configurations when the music was fading
........
r34019 | athrxx | 2008-08-19 08:31:57 +0200 (Tue, 19 Aug 2008) | 1 line
fixed warnings
........
r34021 | anotherguest | 2008-08-19 09:44:35 +0200 (Tue, 19 Aug 2008) | 1 line
Remove Deinit when hiding menu! UI infoprints needed the pixelbuffer.
........
r34022 | peres001 | 2008-08-19 10:08:32 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed segfault when quitting BRA.
........
r34023 | thebluegr | 2008-08-19 10:49:53 +0200 (Tue, 19 Aug 2008) | 1 line
Fix for bug #2057194 - "IHNM: -x option crashes ScummVM, if savegame doesn't exist"
........
r34025 | anotherguest | 2008-08-19 10:54:28 +0200 (Tue, 19 Aug 2008) | 1 line
Don't Use CEikonEnv::Static, get FS from system class instead
........
r34027 | anotherguest | 2008-08-19 11:26:41 +0200 (Tue, 19 Aug 2008) | 1 line
Use the correct and specified datatype int32 instead of only int.
........
r34028 | thebluegr | 2008-08-19 12:05:07 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed regression from commit #33576. Fixes bug #2056282 - "DRASCULA: can't use inventory objects"
........
r34030 | thebluegr | 2008-08-19 12:12:35 +0200 (Tue, 19 Aug 2008) | 1 line
Fix for bug #2057664 - "DRASCULA: No GUI warning when playing from CD"
........
r34032 | fingolfin | 2008-08-19 12:52:39 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed GCC warning
........
r34033 | fingolfin | 2008-08-19 12:58:35 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed 'make install' when building outside srcdir
........
r34034 | buddha_ | 2008-08-19 13:55:20 +0200 (Tue, 19 Aug 2008) | 5 lines
Fix for bug #2057637: FW: Spaceship glitches in demo (regression).
This was caused by assuming in-place decompression is ok, it wasn't,
although AFAIK the original did decompression in-place too.
Changed unpacking to be done not in-place and the glitch vanished.
Also changed the unpacker to also handle uncompressed input data.
........
r34036 | buddha_ | 2008-08-19 15:05:38 +0200 (Tue, 19 Aug 2008) | 6 lines
Fix for bug #2057656: FW: Assert during demo (regression).
Future Wars's Amiga demo is trying to load collision data files
'L8_MK.NEO' and 'L23_MK.NEO' that aren't supplied with the demo.
Previous code crashed when a file couldn't be found,
now it gives a warning instead.
........
r34038 | peres001 | 2008-08-19 16:07:48 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed bug in low-level parser. Block comments weren't interpreted correctly.
........
r34039 | buddha_ | 2008-08-19 16:19:28 +0200 (Tue, 19 Aug 2008) | 2 lines
Fix for bug #2057619: FW: Glitches in title display of demo (regression).
Removed incorrect transparency data used for logo. Now it's shown correctly.
........
r34041 | peres001 | 2008-08-19 16:36:05 +0200 (Tue, 19 Aug 2008) | 1 line
Deleted debug code that slipped in.
........
r34046 | peres001 | 2008-08-20 05:36:49 +0200 (Wed, 20 Aug 2008) | 2 lines
* Enlarged buffer for frame decoding. Crashes in the introduction were caused by a small buffer and subsequent out-of-bound writes.
* Disabled debug code.
........
r34047 | peres001 | 2008-08-20 06:02:12 +0200 (Wed, 20 Aug 2008) | 1 line
Engine now returns to the menu when intro is over.
........
r34048 | eriktorbjorn | 2008-08-20 11:12:11 +0200 (Wed, 20 Aug 2008) | 4 lines
I believe the setVolume() function has to be guarded by a mutex. (I added this to
the Tinsel engine a while back to fix mysterious problems, but forgot to add it
elsewhere.) Maybe this will fix the mysterious IHNM crashes, as well?
........
r34050 | eriktorbjorn | 2008-08-20 11:15:59 +0200 (Wed, 20 Aug 2008) | 2 lines
Moved the mutex locking a bit. (Consistent with how the AGOS engine does it.)
........
r34051 | fingolfin | 2008-08-20 12:18:59 +0200 (Wed, 20 Aug 2008) | 1 line
Extended HashMap debug output
........
r34052 | fingolfin | 2008-08-20 13:07:16 +0200 (Wed, 20 Aug 2008) | 1 line
Unified member names in container/storage classes Array, HashMap and String: _storage, _size, _capacity
........
r34053 | lordhoto | 2008-08-20 16:03:34 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement". (Without Max' compressed backward seeking support for now)
........
r34054 | lordhoto | 2008-08-20 16:24:16 +0200 (Wed, 20 Aug 2008) | 4 lines
- Committed Max' compressed save backseeking support from patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement"
- Extended SCUMM engine to support savegames without thumbnail header. (Increased savegame version to prevent saves to be loaded from older ScummVM versions)
- Fixed KYRA to properly support savegames without thumbnail header.
........
r34055 | lordhoto | 2008-08-20 16:30:40 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch #2055831 "KYRA: ResFileEntry parent cache optimization".
........
r34057 | buddha_ | 2008-08-20 16:56:46 +0200 (Wed, 20 Aug 2008) | 1 line
Fix compilation: Changed 'not' to '!'.
........
r34059 | buddha_ | 2008-08-20 17:06:26 +0200 (Wed, 20 Aug 2008) | 1 line
Added graphics/thumbnail.cpp and graphics/thumbnail.h to MSVC project files.
........
r34060 | lordhoto | 2008-08-20 17:08:00 +0200 (Wed, 20 Aug 2008) | 2 lines
Cleanup of thumbnail saving/loading code.
........
r34061 | lordhoto | 2008-08-20 17:12:36 +0200 (Wed, 20 Aug 2008) | 2 lines
Oops fix save loading after last commit.
........
r34062 | buddha_ | 2008-08-20 17:17:35 +0200 (Wed, 20 Aug 2008) | 1 line
Removed already deleted file engines/scumm/thumbnail.cpp from MSVC project files.
........
r34063 | buddha_ | 2008-08-20 17:58:52 +0200 (Wed, 20 Aug 2008) | 1 line
Renamed graphics/scaler/thumbnail.cpp to thumbnail_intern.cpp. Fixes compiling under MSVC.
........
r34064 | athrxx | 2008-08-20 18:14:10 +0200 (Wed, 20 Aug 2008) | 1 line
tempo fix
........
r34065 | buddha_ | 2008-08-20 19:31:35 +0200 (Wed, 20 Aug 2008) | 4 lines
Fix font loading:
Fixes bug #2058539: OS: Assert starting demo (regression).
May possibly also fix bug #2019344: FW: crash with Amiga Italian version (photocopy room),
but not sure about that because I couldn't reproduce the bug myself.
........
r34067 | athrxx | 2008-08-20 21:57:57 +0200 (Wed, 20 Aug 2008) | 2 lines
- add support for Italian floppy version
- more work on fm-towns music tempo
........
r34072 | lordhoto | 2008-08-20 23:23:30 +0200 (Wed, 20 Aug 2008) | 2 lines
Fixed warning.
........
r34074 | lordhoto | 2008-08-20 23:28:59 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch from bug #2062926 "GCC 4.x versions not detected by configure script".
........
r34076 | athrxx | 2008-08-21 00:38:36 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: fix bug where pitch wheel is processed twice instead of once
........
r34078 | athrxx | 2008-08-21 04:17:52 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: tempo fix for output rates other than 44100 Hz
........
r34079 | athrxx | 2008-08-21 14:04:55 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: increased precision for envelope generator timing and tempo when using "odd" output rates like 48 kHz or 8 kHz
........
r34080 | peres001 | 2008-08-21 14:11:24 +0200 (Thu, 21 Aug 2008) | 1 line
Removed unused code and structures, and a bit of cleanup.
........
r34081 | buddha_ | 2008-08-21 16:14:33 +0200 (Thu, 21 Aug 2008) | 4 lines
Fix for bug #2057619: FW: Glitches in title display of demo (regression).
This fix doesn't seem to break other Future Wars versions like r34039 did.
Some versions of TITRE.ANI use 15 for transparency color, others use 0.
Previously only one of the choices was supported, now both are recognized.
........
r34084 | buddha_ | 2008-08-21 16:43:03 +0200 (Thu, 21 Aug 2008) | 1 line
Fix typo.
........
r34086 | eriktorbjorn | 2008-08-21 16:52:55 +0200 (Thu, 21 Aug 2008) | 2 lines
Fixed warning.
........
r34087 | athrxx | 2008-08-21 20:24:52 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: fixed bug where notes for which the hold flag was set were turned off nonetheless
........
r34089 | peres001 | 2008-08-22 02:19:12 +0200 (Fri, 22 Aug 2008) | 1 line
Implement transition when entering a new location for BRA. Not pixel-perfect, but... let's e happy about it.
........
r34090 | Kirben | 2008-08-22 05:37:43 +0200 (Fri, 22 Aug 2008) | 1 line
Add another 3DO version of Fatty Bear's Birthday Surprise.
........
r34093 | peres001 | 2008-08-22 08:32:12 +0200 (Fri, 22 Aug 2008) | 1 line
Fixed error in parsing.
........
r34096 | fingolfin | 2008-08-22 13:17:12 +0200 (Fri, 22 Aug 2008) | 1 line
code formatting cleanup
........
r34097 | fingolfin | 2008-08-22 13:19:41 +0200 (Fri, 22 Aug 2008) | 1 line
Moved POSIXFilesystemNode class declaration to a new header file, to enable subclassing
........
r34098 | fingolfin | 2008-08-22 13:36:47 +0200 (Fri, 22 Aug 2008) | 1 line
Turned Windows, AmigaOS and POSIX FSFactories into plain classes; no need for them to be singletons (actually true for all other FS factories)
........
r34099 | fingolfin | 2008-08-22 13:41:14 +0200 (Fri, 22 Aug 2008) | 1 line
Symbian backend does not have to implement config file methods, as long as they are identical to those in the SDL backend...
........
r34100 | fingolfin | 2008-08-22 13:45:29 +0200 (Fri, 22 Aug 2008) | 1 line
SDL backend: Simplified openConfigFileForReading/openConfigFileForWriting impl; also init _fsFactory in constructor, as it is needed to load the config file
........
r34101 | fingolfin | 2008-08-22 13:49:34 +0200 (Fri, 22 Aug 2008) | 1 line
Turned SymbianFilesystemFactory from a singleton into a normal class; adapted symbian backend accordingly
........
r34102 | buddha_ | 2008-08-22 14:11:51 +0200 (Fri, 22 Aug 2008) | 1 line
Designate fix for bug #2057619 as a hack, as that's what it is.
........
r34104 | Kirben | 2008-08-22 15:01:23 +0200 (Fri, 22 Aug 2008) | 1 line
Remove warning about change of config file location under Windows, since it is frequently repeated (due to code restructures). The information is mentioned in the README anyway.
........
r34107 | Kirben | 2008-08-23 08:09:30 +0200 (Sat, 23 Aug 2008) | 1 line
Another French version Humongous Catalog and another English DOS version of Fatty Bear's Birthday Surprise.
........
r34113 | drmccoy | 2008-08-23 16:18:12 +0200 (Sat, 23 Aug 2008) | 2 lines
Fixing _itemsMap access (bug #2069177)
........
r34116 | Kirben | 2008-08-24 09:48:44 +0200 (Sun, 24 Aug 2008) | 1 line
Add more versions of HE games.
........
r34119 | aquadran | 2008-08-24 09:54:36 +0200 (Sun, 24 Aug 2008) | 1 line
remove broken code, but i'll add better feature into compression tool
........
r34122 | sev | 2008-08-24 23:28:20 +0200 (Sun, 24 Aug 2008) | 2 lines
Fix inventory.
........
r34124 | sev | 2008-08-24 23:31:20 +0200 (Sun, 24 Aug 2008) | 3 lines
Italian version now has properly translated verbs area as well as numerous
fixes to object names. So new version of packet.005 was prepared.
........
r34126 | sev | 2008-08-24 23:32:37 +0200 (Sun, 24 Aug 2008) | 2 lines
Fixes for Italian strings thanks to glorfindel & co.
........
r34128 | sev | 2008-08-24 23:34:03 +0200 (Sun, 24 Aug 2008) | 2 lines
New drascula.dat with fixed Italian strings
........
r34131 | wjpalenstijn | 2008-08-25 00:09:55 +0200 (Mon, 25 Aug 2008) | 1 line
new tools
........
r34132 | buddha_ | 2008-08-25 01:16:37 +0200 (Mon, 25 Aug 2008) | 3 lines
Fix for bug #2055912: FW: incrustSprite fails on savegame loading.
What little testing I did, this seems to work, but more testing
would be nice.
........
r34135 | peres001 | 2008-08-25 08:32:08 +0200 (Mon, 25 Aug 2008) | 1 line
Added workaround for bug 2070751, long standing issue with item matching exposed after revision 32873.
........
r34138 | knakos | 2008-08-25 10:11:52 +0200 (Mon, 25 Aug 2008) | 1 line
patch 1984130: Add Tremolo info
........
r34141 | knakos | 2008-08-25 10:48:46 +0200 (Mon, 25 Aug 2008) | 1 line
patch 1868881: ini option to disable doubletap rmb
........
r34144 | peres001 | 2008-08-25 11:35:22 +0200 (Mon, 25 Aug 2008) | 1 line
Fixed regression: show mouse and enable input in NS Demo.
........
r34146 | buddha_ | 2008-08-25 14:00:38 +0200 (Mon, 25 Aug 2008) | 1 line
Added a warning to bug #2055912's fix committed in revision 34132.
........
r34149 | lordhoto | 2008-08-25 15:52:10 +0200 (Mon, 25 Aug 2008) | 2 lines
Added short delay(Millis) call while waiting for text input, should reduce CPU usage a little bit.
........
r34152 | thebluegr | 2008-08-25 16:55:11 +0200 (Mon, 25 Aug 2008) | 3 lines
Fix for bug #2073159 - "MICKEY: Incomplete computer message".
Random numbers are calculated from 1 onwards in the preAGI engines, but there was an off-by one error. I'm currently hesitant to add this fix to the 0.12.0 branch, as I'm unsure if it has any possible regressions in Troll's Tale or Winnie the Pooh
........
r34153 | buddha_ | 2008-08-25 17:04:48 +0200 (Mon, 25 Aug 2008) | 1 line
Added Cinematique archive file unpacker and script disassembler to tools. NOT polished code so caveat emptor.
........
r34154 | thebluegr | 2008-08-25 17:07:05 +0200 (Mon, 25 Aug 2008) | 1 line
Fix for bug #2062024 - "DRASCULA: Error talking with blind man"
........
r34156 | buddha_ | 2008-08-25 17:14:20 +0200 (Mon, 25 Aug 2008) | 1 line
Added info about cine_tools to tools/README. Also added a couple of FIXMEs to the cine_tools files about missing endian safeness.
........
r34157 | lordhoto | 2008-08-25 17:14:29 +0200 (Mon, 25 Aug 2008) | 2 lines
Implemented continous screen updating while waiting for text input in v2 GUI. (based on LoK implementation)
........
r34160 | thebluegr | 2008-08-25 17:58:45 +0200 (Mon, 25 Aug 2008) | 2 lines
Fix for original game bug with the wall plug in chapter 5.
Fixes bug #2059621 - DRASCULA: Plug bug
........
r34163 | buddha_ | 2008-08-25 19:41:00 +0200 (Mon, 25 Aug 2008) | 1 line
Reverted revision 34156 and revision 34153 (extract_cine and decine got properly placed in revision 34162).
........
r34164 | knakos | 2008-08-25 19:43:56 +0200 (Mon, 25 Aug 2008) | 1 line
Update readme
........
r34169 | eriktorbjorn | 2008-08-25 20:47:27 +0200 (Mon, 25 Aug 2008) | 5 lines
Refined the workaround for wrongly compressed audio. If the sample rate is given
as 11025 Hz, it should be 11840 Hz. However, a fixed version of compress_queen
won't necessarily produce files with that sample rate, since LAME will resample
the sounds to 12000 Hz. I.e. we can only override the rate if it's exactly 11025.
........
r34173 | wjpalenstijn | 2008-08-25 21:22:16 +0200 (Mon, 25 Aug 2008) | 1 line
package tools_gui as scummvm_tools_gui
........
r34179 | thebluegr | 2008-08-26 09:48:19 +0200 (Tue, 26 Aug 2008) | 1 line
Cleanup
........
r34180 | thebluegr | 2008-08-26 10:05:36 +0200 (Tue, 26 Aug 2008) | 1 line
Merged talk_vonBraun and talk_vonBraunpuerta
........
r34181 | thebluegr | 2008-08-26 10:21:21 +0200 (Tue, 26 Aug 2008) | 1 line
Simplified several calls to copyBackground()
........
r34182 | thebluegr | 2008-08-26 10:35:02 +0200 (Tue, 26 Aug 2008) | 2 lines
talk_dr_grande -> talk_drascula_big
talk_baul -> talk_trunk
........
r34183 | thebluegr | 2008-08-26 12:59:59 +0200 (Tue, 26 Aug 2008) | 1 line
Removed some unneeded sanity checks that have been introduced with the latest cleanups
........
r34184 | Kirben | 2008-08-26 13:15:01 +0200 (Tue, 26 Aug 2008) | 1 line
Add more versions of HE games.
........
r34185 | peres001 | 2008-08-26 14:15:11 +0200 (Tue, 26 Aug 2008) | 1 line
Cleanup.
........
r34186 | thebluegr | 2008-08-26 14:34:05 +0200 (Tue, 26 Aug 2008) | 1 line
Correct fix for bug #2073159 - "MICKEY: Incomplete computer message"
........
r34187 | lordhoto | 2008-08-26 15:51:26 +0200 (Tue, 26 Aug 2008) | 2 lines
Fixed typo. (Thanks to salty-horse for spotting it).
........
r34188 | lordhoto | 2008-08-26 15:56:58 +0200 (Tue, 26 Aug 2008) | 2 lines
And for all of those who love recompiling most of ScummVM... fixed typo properly :-P
........
r34189 | thebluegr | 2008-08-26 16:26:43 +0200 (Tue, 26 Aug 2008) | 1 line
Fix for bug #2057200 - "IHNM: Invisible inventory objects"
........
r34190 | thebluegr | 2008-08-27 12:00:32 +0200 (Wed, 27 Aug 2008) | 1 line
Document some animations
........
r34191 | fingolfin | 2008-08-27 19:41:05 +0200 (Wed, 27 Aug 2008) | 1 line
cleanup
........
r34192 | fingolfin | 2008-08-27 20:21:03 +0200 (Wed, 27 Aug 2008) | 1 line
Slightly cleaned up version of patch #2072006: Enhance OSystem_SDL::setupIcon
........
r34193 | fingolfin | 2008-08-27 20:38:06 +0200 (Wed, 27 Aug 2008) | 1 line
Slightly modified form of patch #2043093: OS/2 patches for posix-fs
........
r34194 | fingolfin | 2008-08-27 20:52:21 +0200 (Wed, 27 Aug 2008) | 1 line
Partial commit of patch #2012839: Atari Patch for adding Native MIDI and Fix Compile
........
r34196 | fingolfin | 2008-08-27 21:29:41 +0200 (Wed, 27 Aug 2008) | 1 line
Fix bug #2078922: DW: Pushing ESC repeatedly at beginning causes odd behavior
........
r34197 | fingolfin | 2008-08-27 22:31:22 +0200 (Wed, 27 Aug 2008) | 1 line
FSNode code: Merged most versions of lastPathComponent() into one new AbstractFilesystemNode::lastPathComponent() method, with customizable path separator character
........
r34198 | fingolfin | 2008-08-27 22:41:28 +0200 (Wed, 27 Aug 2008) | 1 line
Removed various uses of scumm_stricmp by the more readable String::equalsIgnoreCase and String:: compareToIgnoreCase
........
r34200 | fingolfin | 2008-08-28 11:03:43 +0200 (Thu, 28 Aug 2008) | 1 line
Some extra HashMap tests
........
r34201 | fingolfin | 2008-08-29 11:44:05 +0200 (Fri, 29 Aug 2008) | 1 line
Made out-of-memory error in SCUMM a bit more verbose
........
r34205 | lordhoto | 2008-08-30 00:04:15 +0200 (Sat, 30 Aug 2008) | 1 line
Updated msvc8 and msvc9 project files for latest FS changes.
........
r34206 | peres001 | 2008-08-30 12:27:20 +0200 (Sat, 30 Aug 2008) | 1 line
Moved mouse cursor loading/handling to Input class.
........
r34208 | eriktorbjorn | 2008-08-30 14:54:54 +0200 (Sat, 30 Aug 2008) | 2 lines
Added a whitespace, just for salty-horse.
........
r34209 | peres001 | 2008-08-30 17:49:54 +0200 (Sat, 30 Aug 2008) | 1 line
Removed global g_system.
........
r34210 | fingolfin | 2008-08-30 23:03:15 +0200 (Sat, 30 Aug 2008) | 1 line
TINSEL: Added support for the 3,4 and 5 FLAGS (multi lingual) versions of DW (only 4 flags version has been tested; see also bug #2048383)
........
r34211 | fingolfin | 2008-08-30 23:43:36 +0200 (Sat, 30 Aug 2008) | 1 line
cleanup
........
r34212 | fingolfin | 2008-08-30 23:51:13 +0200 (Sat, 30 Aug 2008) | 1 line
TINSEL: Write config changes to disk
........
r34213 | fingolfin | 2008-08-31 00:09:35 +0200 (Sun, 31 Aug 2008) | 1 line
TINSEL: Remove some unused code; and duplicated the 4-FLAGS version detection entry (one copy for each language) for the user's convenience
........
r34214 | fingolfin | 2008-08-31 00:10:48 +0200 (Sun, 31 Aug 2008) | 1 line
TINSEL: The engine version is an integer, not a bitfield
........
r34215 | fingolfin | 2008-08-31 00:16:59 +0200 (Sun, 31 Aug 2008) | 1 line
cleanup
........
r34216 | fingolfin | 2008-08-31 00:26:16 +0200 (Sun, 31 Aug 2008) | 1 line
Fix (?) Solaris detection in some workaround code in the MT-32 emulator
........
r34217 | drmccoy | 2008-08-31 01:59:46 +0200 (Sun, 31 Aug 2008) | 2 lines
Added some The Last Dynasty stubs
........
r34219 | peres001 | 2008-08-31 07:18:25 +0200 (Sun, 31 Aug 2008) | 1 line
Uniformed the interface of Parallaction class (and its hierarchy) with regards of gui code, which is now independent of engine version.
........
r34220 | peres001 | 2008-08-31 08:14:45 +0200 (Sun, 31 Aug 2008) | 1 line
Moved save/load code into SaveLoad class.
........
r34221 | peres001 | 2008-08-31 10:27:40 +0200 (Sun, 31 Aug 2008) | 1 line
Removed extra semicolon detected by salty-horse pesky compiler.
........
r34222 | peres001 | 2008-08-31 11:30:16 +0200 (Sun, 31 Aug 2008) | 2 lines
Cleanup.
........
r34223 | peres001 | 2008-08-31 12:24:32 +0200 (Sun, 31 Aug 2008) | 1 line
More cleanup.
........
r34224 | peres001 | 2008-08-31 12:43:32 +0200 (Sun, 31 Aug 2008) | 1 line
Fixed leak with Input class, introduced in commit 34206.
........
r34225 | drmccoy | 2008-08-31 13:37:07 +0200 (Sun, 31 Aug 2008) | 2 lines
Shutting up a warning on systems where char is signed by default
........
r34227 | peres001 | 2008-08-31 15:58:17 +0200 (Sun, 31 Aug 2008) | 4 lines
* Added Archive, an interface for searching into file containers.
* Added FSDirectory, an Archive implementation that models a directory from the filesystem.
* Added SearchSet, an Archive implementation that allows searching multiple Archives.
See patch 2034983 on sf.net.
........
r34228 | fingolfin | 2008-08-31 17:30:07 +0200 (Sun, 31 Aug 2008) | 1 line
Fix warnings
........
r34234 | lordhoto | 2008-09-01 01:11:55 +0200 (Mon, 01 Sep 2008) | 2 lines
Added newly added archive.cpp to the build system, just in case someone wants to play with the code and wonders about errors while linking.
........
r34235 | thebluegr | 2008-09-01 12:07:48 +0200 (Mon, 01 Sep 2008) | 1 line
Updated all MSVC project files with the latest changes to the code (gob and parallaction engines and the file system)
........
r34236 | thebluegr | 2008-09-01 12:09:48 +0200 (Mon, 01 Sep 2008) | 1 line
Silence MSVC warning about potentially uninitialized variable
........
r34237 | fingolfin | 2008-09-01 12:54:03 +0200 (Mon, 01 Sep 2008) | 1 line
New Queue class, from RTL branch
........
r34239 | lordhoto | 2008-09-01 17:39:48 +0200 (Mon, 01 Sep 2008) | 2 lines
Fixed warnings.
........
r34240 | lordhoto | 2008-09-01 18:52:09 +0200 (Mon, 01 Sep 2008) | 3 lines
- Added tests for newly added Common::Queue
- Changed Common::Queue::front and Common::Queue::back to return references instead of values
........
r34241 | fingolfin | 2008-09-01 19:30:03 +0200 (Mon, 01 Sep 2008) | 1 line
First part of GSoC2008 RTL branch merge
........
r34242 | fingolfin | 2008-09-01 19:46:05 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: AGI
........
r34243 | fingolfin | 2008-09-01 19:46:53 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: AGOS
........
r34244 | fingolfin | 2008-09-01 19:47:36 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: CINE
........
r34245 | fingolfin | 2008-09-01 19:50:00 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: GOB
........
r34246 | fingolfin | 2008-09-01 19:52:50 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: KYRA
........
r34247 | fingolfin | 2008-09-01 19:55:52 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: QUEEN
........
r34248 | lordhoto | 2008-09-01 20:14:55 +0200 (Mon, 01 Sep 2008) | 2 lines
Cleanup.
........
r34249 | lordhoto | 2008-09-01 20:26:28 +0200 (Mon, 01 Sep 2008) | 2 lines
Formatting.
........
r34251 | fingolfin | 2008-09-01 22:18:17 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: LURE
........
r34252 | fingolfin | 2008-09-01 22:19:28 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SAGA
........
r34253 | fingolfin | 2008-09-01 22:20:20 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SCUMM
........
r34254 | fingolfin | 2008-09-01 22:20:57 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SKY
........
r34255 | fingolfin | 2008-09-01 22:21:30 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SWORD1
........
r34256 | fingolfin | 2008-09-01 22:21:53 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SWORD2
........
r34257 | fingolfin | 2008-09-01 22:22:10 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: TINSEL
........
r34258 | fingolfin | 2008-09-01 22:22:29 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: TOUCHE
........
r34259 | athrxx | 2008-09-01 22:23:25 +0200 (Mon, 01 Sep 2008) | 1 line
- kyra: fm-towns/pc-98 audio: restructured driver, added rhythm channel data
........
r34260 | fingolfin | 2008-09-01 22:31:44 +0200 (Mon, 01 Sep 2008) | 1 line
Clarified some comments
........
r34261 | fingolfin | 2008-09-01 22:41:43 +0200 (Mon, 01 Sep 2008) | 1 line
Clarified clarification ;)
........
r34262 | fingolfin | 2008-09-01 23:06:32 +0200 (Mon, 01 Sep 2008) | 1 line
Document each MetaEngineFeature (instead of listing just 'examples'). Wording could be better, feel free to improve it
........
r34263 | fingolfin | 2008-09-01 23:13:11 +0200 (Mon, 01 Sep 2008) | 1 line
TINSEL: Enabled listSaves support
........
r34264 | fingolfin | 2008-09-01 23:30:38 +0200 (Mon, 01 Sep 2008) | 1 line
cleanup
........
r34265 | thebluegr | 2008-09-02 01:36:59 +0200 (Tue, 02 Sep 2008) | 1 line
Silence MSVC warning about empty switch statement
........
r34266 | thebluegr | 2008-09-02 01:37:24 +0200 (Tue, 02 Sep 2008) | 1 line
Silence MSVC warning about empty switch statement
........
r34267 | joostp | 2008-09-02 02:31:27 +0200 (Tue, 02 Sep 2008) | 2 lines
fix Virgin logo screen breakage that was introduced in the RTL merge
........
r34268 | peres001 | 2008-09-02 03:58:55 +0200 (Tue, 02 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: PARALLACTION
........
r34269 | thebluegr | 2008-09-02 09:32:09 +0200 (Tue, 02 Sep 2008) | 1 line
Added new files to the MSVC projects (engines/dialogs.* and common/queue.h)
........
r34270 | thebluegr | 2008-09-02 09:59:52 +0200 (Tue, 02 Sep 2008) | 1 line
Changed the MSVC optimization settings for the release version of all current engines, according to the settings proposed in patch #1877032 - "better optimization settings for msvc9". SSE has NOT been enabled by default though, as it's not available under 64-bit platforms. Updated the MSVC 8 -> MSVC 7/7.1 batch file accordingly
........
r34271 | thebluegr | 2008-09-02 10:02:40 +0200 (Tue, 02 Sep 2008) | 1 line
Added the missing tinsel engine project files for MSVC 7/7.1
........
r34272 | fingolfin | 2008-09-02 13:32:38 +0200 (Tue, 02 Sep 2008) | 1 line
Added two new global funcs which ease proper handling of 'path' strings: Common::lastPathComponent() and Common::normalizePath()
........
r34273 | fingolfin | 2008-09-02 13:34:12 +0200 (Tue, 02 Sep 2008) | 1 line
Revised HashMap implementation
........
r34274 | thebluegr | 2008-09-02 13:42:15 +0200 (Tue, 02 Sep 2008) | 2 lines
Enabled the new optimizations for older versions of MSVC as well
Also, included the tinsel engine library for the release version as well (fixes compilation of the release version)
........
r34275 | lordhoto | 2008-09-02 15:05:43 +0200 (Tue, 02 Sep 2008) | 2 lines
Added missing include.
........
r34276 | lordhoto | 2008-09-02 15:11:54 +0200 (Tue, 02 Sep 2008) | 2 lines
Handle OSystem::lockScreen fail in default OSystem::clearScreen implementation.
........
r34277 | lordhoto | 2008-09-02 15:13:02 +0200 (Tue, 02 Sep 2008) | 2 lines
Updated NULL backend for FS changes.
........
r34278 | lordhoto | 2008-09-02 15:16:51 +0200 (Tue, 02 Sep 2008) | 2 lines
Fixed copy&paste error when checking y and h of a widget on layout change.
........
r34279 | lordhoto | 2008-09-02 15:17:40 +0200 (Tue, 02 Sep 2008) | 2 lines
Fake 320x200 resolution instead of 200x320.
........
r34281 | lordhoto | 2008-09-02 15:27:26 +0200 (Tue, 02 Sep 2008) | 2 lines
Applied my patch from -devel, which reenables GMM opening via F6.
........
r34282 | lordhoto | 2008-09-02 16:36:47 +0200 (Tue, 02 Sep 2008) | 4 lines
Cleanup: Remove now unneeded KyraEngine_v1::quitGame.
Peres proposal for this commit log was: 'fixing .... as peres pointed out in his very interesting mail on -devel that everybody should read'.
........
r34283 | fingolfin | 2008-09-02 17:19:31 +0200 (Tue, 02 Sep 2008) | 1 line
Modified POSIX FSNode implementation to use Common::normalizePath & Common::lastPathComponent; added a TODO regarding relative paths
........
r34284 | fingolfin | 2008-09-02 18:35:16 +0200 (Tue, 02 Sep 2008) | 1 line
Change FilesystemNode::getChild to new desired behavior: namely, that it should return valid nodes even for names for which no child exists (yet?) -- mail to scummvm-devel pending
........
r34286 | drmccoy | 2008-09-02 22:15:42 +0200 (Tue, 02 Sep 2008) | 2 lines
Urban Runner stubs
........
r34287 | drmccoy | 2008-09-02 23:29:06 +0200 (Tue, 02 Sep 2008) | 2 lines
Added French Bargon Attack, as supplied by kizkoool in bugreport #2089734
........
r34288 | athrxx | 2008-09-02 23:31:53 +0200 (Tue, 02 Sep 2008) | 1 line
some minor bug fixes
........
r34290 | Kirben | 2008-09-03 03:47:01 +0200 (Wed, 03 Sep 2008) | 1 line
Add Nintendo Wii versions of Freddi Fish 1 and Pajama Sam 1.
........
r34291 | Kirben | 2008-09-03 04:06:11 +0200 (Wed, 03 Sep 2008) | 1 line
Add another Dutch demo of Pajama Sam 1.
........
r34292 | thebluegr | 2008-09-03 09:32:59 +0200 (Wed, 03 Sep 2008) | 1 line
Updated gob MSVC project files for commit #34286
........
r34293 | fingolfin | 2008-09-03 10:57:39 +0200 (Wed, 03 Sep 2008) | 1 line
If launching scummvm with no game selected, clear the transient domain (and hence the effect of all command line args) before opening the launcher (may cause regressions)
........
r34294 | fingolfin | 2008-09-03 10:58:19 +0200 (Wed, 03 Sep 2008) | 1 line
In the launcher load dialog code, store the save_slot in the transient domain (fixing bug #2089740)
........
r34295 | thebluegr | 2008-09-03 11:03:21 +0200 (Wed, 03 Sep 2008) | 1 line
Cleanup
........
r34296 | thebluegr | 2008-09-03 11:55:29 +0200 (Wed, 03 Sep 2008) | 1 line
Silence MSVC warning about ambiguous usage of CLIP
........
r34297 | thebluegr | 2008-09-03 11:58:28 +0200 (Wed, 03 Sep 2008) | 1 line
Commented out currently broken code, adding a FIXME
........
r34298 | thebluegr | 2008-09-03 12:00:43 +0200 (Wed, 03 Sep 2008) | 1 line
Silence MSVC warning about uninitialized variables
........
r34299 | thebluegr | 2008-09-03 12:10:45 +0200 (Wed, 03 Sep 2008) | 1 line
Fix for MSVC warning about ambiguous usage of MIN
........
r34300 | fingolfin | 2008-09-03 12:11:36 +0200 (Wed, 03 Sep 2008) | 1 line
Added new StdioStream class, a thin wrapper around FILE
........
r34301 | fingolfin | 2008-09-03 12:40:46 +0200 (Wed, 03 Sep 2008) | 1 line
Added new AbstractFilesystemNode::openForReading & ::openForWriting method, based on StdioStream; changed FilesystemNode to use them
........
r34302 | fingolfin | 2008-09-03 13:22:51 +0200 (Wed, 03 Sep 2008) | 1 line
Moved FilesystemNode / FSList to namespace Common; also got rid of some 'typedef Common::String String;' name aliases
........
r34303 | fingolfin | 2008-09-03 13:49:02 +0200 (Wed, 03 Sep 2008) | 1 line
Moved StdioStream to its own files inside backends
........
r34304 | fingolfin | 2008-09-03 14:56:46 +0200 (Wed, 03 Sep 2008) | 1 line
Pushed AbstractFilesystemNode::openForReading() / openForWriting() impls out to backends
........
r34305 | Kirben | 2008-09-03 15:49:24 +0200 (Wed, 03 Sep 2008) | 1 line
Added more versions of HE games.
........
r34306 | thebluegr | 2008-09-03 16:06:54 +0200 (Wed, 03 Sep 2008) | 1 line
Updated MSVC project files for commit #34303
........
r34307 | fingolfin | 2008-09-03 16:55:19 +0200 (Wed, 03 Sep 2008) | 1 line
POSIX FSNode: got rid of Double-slashes in paths for childs of the root; simplified code
........
r34308 | fingolfin | 2008-09-03 17:22:19 +0200 (Wed, 03 Sep 2008) | 1 line
Some cleanup by peres
........
r34309 | fingolfin | 2008-09-03 17:58:40 +0200 (Wed, 03 Sep 2008) | 1 line
TODO: bdf_getline seems to duplicate code from SeekableReadStream::readLine(_new) -> fix that
........
r34310 | fingolfin | 2008-09-03 18:56:40 +0200 (Wed, 03 Sep 2008) | 1 line
Moved check for shouldRTL() from engines to scummvm_main
........
r34311 | fingolfin | 2008-09-03 19:06:24 +0200 (Wed, 03 Sep 2008) | 1 line
clarified comment
........
r34312 | fingolfin | 2008-09-03 19:07:13 +0200 (Wed, 03 Sep 2008) | 1 line
Changed Archive::openFile to return a SeekableReadStream* instead of a FilePtr
........
r34313 | fingolfin | 2008-09-03 19:39:18 +0200 (Wed, 03 Sep 2008) | 1 line
Modified Common::Str to use exponential growth for its storage; also changed the meaning of 'capacity' from 'max length of string' to 'size of storage' (i.e. added one)
........
r34314 | fingolfin | 2008-09-03 19:46:42 +0200 (Wed, 03 Sep 2008) | 1 line
Removed unused readLine code from the MT-32 emu
........
r34315 | fingolfin | 2008-09-03 19:53:25 +0200 (Wed, 03 Sep 2008) | 1 line
Renamed SeekableReadStream::readLine to SeekableReadStream::readLine_OLD; added a new alternate SeekableReadStream::readLine() instead
........
r34316 | fingolfin | 2008-09-03 20:07:31 +0200 (Wed, 03 Sep 2008) | 1 line
Fixed Stream::readLine implementation to match its doxygen comment
........
r34317 | fingolfin | 2008-09-03 20:38:01 +0200 (Wed, 03 Sep 2008) | 1 line
Fix nasty off-by-one errors
........
r34318 | fingolfin | 2008-09-03 20:40:49 +0200 (Wed, 03 Sep 2008) | 1 line
Changed some code to use the new Stream::readLine() method
........
r34319 | lordhoto | 2008-09-03 21:07:38 +0200 (Wed, 03 Sep 2008) | 2 lines
Minor formatting cleanup.
........
r34320 | mthreepwood | 2008-09-03 23:37:19 +0200 (Wed, 03 Sep 2008) | 1 line
correct a typo (thanks to salty-horse)
........
r34323 | Kirben | 2008-09-04 10:11:35 +0200 (Thu, 04 Sep 2008) | 1 line
Correct HE version for Wii version of Freddi Fish 1.
........
r34324 | joostp | 2008-09-04 10:16:39 +0200 (Thu, 04 Sep 2008) | 2 lines
remove deprecated SCUMMVM_SAVEPATH define -- pass default savepath to DefaultSaveFileManager ctor
........
r34326 | joostp | 2008-09-04 10:34:02 +0200 (Thu, 04 Sep 2008) | 2 lines
move save directory detection/creation from main() to OSystem_PSP::initBackend()
........
r34328 | Kirben | 2008-09-04 16:12:27 +0200 (Thu, 04 Sep 2008) | 1 line
Add missing case in o100_resourceRoutines.
........
r34329 | drmccoy | 2008-09-04 19:39:22 +0200 (Thu, 04 Sep 2008) | 2 lines
Ooops, adding Lost in Time and Woodruff
........
r34332 | drmccoy | 2008-09-04 21:20:51 +0200 (Thu, 04 Sep 2008) | 2 lines
Added another version of Lost in Time CD, as supplied by SiRoCs in bug report #2093672
........
r34334 | fingolfin | 2008-09-04 22:03:08 +0200 (Thu, 04 Sep 2008) | 1 line
Changed FSDirectory::getSubDirectory to return a FSDirectory pointer instead of a SharedPtr
........
r34336 | eriktorbjorn | 2008-09-04 23:40:32 +0200 (Thu, 04 Sep 2008) | 2 lines
Use readLine() instead of readLine_OLD().
........
r34338 | anotherguest | 2008-09-05 13:06:27 +0200 (Fri, 05 Sep 2008) | 1 line
Updated buildscripts to support tinsel
........
r34339 | anotherguest | 2008-09-05 13:09:29 +0200 (Fri, 05 Sep 2008) | 1 line
Updated package revision no to 0.13. Updated default engine list
........
r34340 | anotherguest | 2008-09-05 13:31:51 +0200 (Fri, 05 Sep 2008) | 1 line
Updated Symbian OS file actions with ferror and fflush.
........
r34343 | peres001 | 2008-09-05 13:41:39 +0200 (Fri, 05 Sep 2008) | 1 line
Removed useless dependencies from common/file.h in common code. When complete removal was not possibile, dependency has been pushed to the cpp files from the headers.
........
r34344 | anotherguest | 2008-09-05 13:55:58 +0200 (Fri, 05 Sep 2008) | 1 line
Added two new files
........
r34345 | fingolfin | 2008-09-05 13:59:33 +0200 (Fri, 05 Sep 2008) | 1 line
Ported AMIGA specific file buffering 'hack' from class File to StdioStream
........
r34346 | anotherguest | 2008-09-05 14:02:15 +0200 (Fri, 05 Sep 2008) | 1 line
Updated filehandling for Symbian OS
........
r34347 | anotherguest | 2008-09-05 14:30:19 +0200 (Fri, 05 Sep 2008) | 1 line
Updated build script with new dialog.cpp
........
r34348 | anotherguest | 2008-09-05 14:53:43 +0200 (Fri, 05 Sep 2008) | 1 line
Still need to get that build working. Readjust buildscript
........
r34349 | thebluegr | 2008-09-05 15:02:03 +0200 (Fri, 05 Sep 2008) | 1 line
Hopefully fixed the chaos with the SAGA volume values. This also fixes the broken volume introduced with the introduction of the RTL code in the engine
........
r34350 | anotherguest | 2008-09-05 15:03:31 +0200 (Fri, 05 Sep 2008) | 1 line
Add missing dialogs.cpp
........
r34351 | anotherguest | 2008-09-05 15:13:51 +0200 (Fri, 05 Sep 2008) | 1 line
ADded Tinsel as supported engine strings
........
r34352 | Kirben | 2008-09-05 15:35:27 +0200 (Fri, 05 Sep 2008) | 1 line
Use exact case numbers, to avoid unneeded subtractions.
........
r34353 | anotherguest | 2008-09-05 16:11:23 +0200 (Fri, 05 Sep 2008) | 1 line
Enum needs to be minimum four chars to compile (32 bit number I guess)
........
r34356 | fingolfin | 2008-09-05 19:23:44 +0200 (Fri, 05 Sep 2008) | 1 line
whitespace 'fix'
........
r34357 | eriktorbjorn | 2008-09-05 19:34:38 +0200 (Fri, 05 Sep 2008) | 2 lines
Set the date for 0.12.0.
........
r34359 | peres001 | 2008-09-05 20:24:41 +0200 (Fri, 05 Sep 2008) | 2 lines
* Implemented a default matchPattern for Archive subclasses (courtesy of Fingolfin).
* Fixed bug in FSDirectory::matchPattern.
........
r34360 | peres001 | 2008-09-05 20:28:25 +0200 (Fri, 05 Sep 2008) | 1 line
Made FSDirectory use the default matchPattern implementation.
........
r34361 | anotherguest | 2008-09-05 20:45:04 +0200 (Fri, 05 Sep 2008) | 1 line
Remove usage of main_features.inl and the file
........
r34362 | anotherguest | 2008-09-05 20:49:13 +0200 (Fri, 05 Sep 2008) | 1 line
Change location of create fs factory for Symbian!
........
r34363 | anotherguest | 2008-09-05 21:03:30 +0200 (Fri, 05 Sep 2008) | 1 line
Add symbian implementations to create read/write configfile handles
........
r34364 | fingolfin | 2008-09-05 22:07:34 +0200 (Fri, 05 Sep 2008) | 1 line
Moved matchString from util.* to str.*; added new String::matchString method; fixed matchString doxygen comment (it confused pattern & string); added unit tests for matchString
........
r34365 | fingolfin | 2008-09-05 22:08:29 +0200 (Fri, 05 Sep 2008) | 1 line
Make use of String::matchString
........
r34366 | fingolfin | 2008-09-05 22:26:36 +0200 (Fri, 05 Sep 2008) | 1 line
Fix class FSDirectory (matchPattern would call getAllNames would call matchPattern would call ...); some cleanup
........
r34367 | fingolfin | 2008-09-05 22:29:03 +0200 (Fri, 05 Sep 2008) | 1 line
Optimized matchString for the common case where there is a trailing * (if that is the case, abort immediately instead of scanning the rest of the string)
........
r34368 | fingolfin | 2008-09-05 22:42:41 +0200 (Fri, 05 Sep 2008) | 1 line
Some tweaks to help (?) OS/2
........
r34369 | wjpalenstijn | 2008-09-05 22:53:30 +0200 (Fri, 05 Sep 2008) | 1 line
additional Common::String tests
........
r34370 | fingolfin | 2008-09-06 00:12:46 +0200 (Sat, 06 Sep 2008) | 1 line
Added simple ZipArchive class, and changed some GUI code to use it, instead of the ugly C API to the unzip code
........
r34371 | fingolfin | 2008-09-06 00:14:43 +0200 (Sat, 06 Sep 2008) | 1 line
Updated some copyright strings to 2001-2008
........
r34373 | fingolfin | 2008-09-06 00:16:29 +0200 (Sat, 06 Sep 2008) | 1 line
Added Chris to credits
........
r34375 | Kirben | 2008-09-06 03:02:45 +0200 (Sat, 06 Sep 2008) | 1 line
Add debugInput opcode for HE 100 games.
........
r34378 | Kirben | 2008-09-06 09:03:38 +0200 (Sat, 06 Sep 2008) | 1 line
Add Wii version of SPY Fox 1.
........
r34381 | thebluegr | 2008-09-06 10:37:03 +0200 (Sat, 06 Sep 2008) | 1 line
Added missing common/archive.*
........
r34382 | anotherguest | 2008-09-06 12:30:05 +0200 (Sat, 06 Sep 2008) | 2 lines
Portdefs cleanup, use snprintf from SDL and not sprintf (Which can cause memory overwrites).
Use bsearch implementation from WINCE port.
........
r34384 | fingolfin | 2008-09-06 18:46:28 +0200 (Sat, 06 Sep 2008) | 1 line
Added some unit tests for Stream::readLine_NEW, and clarified that readLine_NEW is essentially fgets in disguise
........
r34385 | fingolfin | 2008-09-06 19:00:50 +0200 (Sat, 06 Sep 2008) | 1 line
Unlike ferror, our Stream::ioFailed() is also supposed to return true when the end of stream has been reached
........
r34389 | fingolfin | 2008-09-06 22:34:21 +0200 (Sat, 06 Sep 2008) | 1 line
ScummFile: Don't use the File::_ioFailed flag, rather track the io status separately; also, changed eof() -> eos()
........
r34390 | fingolfin | 2008-09-06 22:36:47 +0200 (Sat, 06 Sep 2008) | 1 line
MT32 emu: eof -> eos
........
r34391 | fingolfin | 2008-09-06 22:49:48 +0200 (Sat, 06 Sep 2008) | 1 line
Switched class File & DumpFile to use StdioStream internally
........
r34393 | fingolfin | 2008-09-06 23:04:42 +0200 (Sat, 06 Sep 2008) | 1 line
Removed last traces of fopen / FILE from common/file.cpp
........
r34394 | fingolfin | 2008-09-06 23:09:34 +0200 (Sat, 06 Sep 2008) | 1 line
Clarified / fixed some Common::Archive doxygen comments
........
r34396 | fingolfin | 2008-09-06 23:23:08 +0200 (Sat, 06 Sep 2008) | 1 line
Got rid of File::eof()
........
r34397 | lordhoto | 2008-09-07 00:09:34 +0200 (Sun, 07 Sep 2008) | 1 line
Added hasArchive to SearchSet.
........
r34399 | anotherguest | 2008-09-07 12:57:28 +0200 (Sun, 07 Sep 2008) | 1 line
Remove symbian defines from stdiostream.cpp
........
r34400 | anotherguest | 2008-09-07 14:37:14 +0200 (Sun, 07 Sep 2008) | 1 line
StdioStream implemented with Symbian file handling.
........
r34401 | anotherguest | 2008-09-07 14:38:35 +0200 (Sun, 07 Sep 2008) | 1 line
Updated to include SymbianStream instead of StdioStream
........
r34402 | anotherguest | 2008-09-07 14:39:56 +0200 (Sun, 07 Sep 2008) | 1 line
Need to have own implementation of snprintf and vsnprintf.
........
r34403 | anotherguest | 2008-09-07 14:54:26 +0200 (Sun, 07 Sep 2008) | 1 line
Remove SYMBIAN special handing from default handler.
........
r34404 | drmccoy | 2008-09-07 15:16:58 +0200 (Sun, 07 Sep 2008) | 2 lines
Added another demo version of Gobliiins (bug #2098412)
........
r34405 | anotherguest | 2008-09-07 15:17:21 +0200 (Sun, 07 Sep 2008) | 1 line
H file cleanup, remove old vibra support
........
r34407 | anotherguest | 2008-09-07 15:40:30 +0200 (Sun, 07 Sep 2008) | 3 lines
Updated readme about usage of snprintf source
Added vsnprintf implementation.
Cleanout SymbianOS.cpp from old file functions.
........
r34408 | fingolfin | 2008-09-07 17:16:45 +0200 (Sun, 07 Sep 2008) | 1 line
Temporary workaround for bug #2098279: ALL: Game path with no trailing backslash fails
........
r34409 | drmccoy | 2008-09-07 17:21:52 +0200 (Sun, 07 Sep 2008) | 2 lines
Clipping setMousePos() parameters to sane values
........
r34411 | drmccoy | 2008-09-07 17:29:47 +0200 (Sun, 07 Sep 2008) | 2 lines
Actually, /now/ the values are sane ^^; (also fixes Ween mouse position bug #2046244)
........
r34413 | drmccoy | 2008-09-07 17:39:06 +0200 (Sun, 07 Sep 2008) | 2 lines
Added a spanish floppy version of Gob3, as supplied by SiRoCs in bug report #2098621
........
r34415 | drmccoy | 2008-09-07 18:27:04 +0200 (Sun, 07 Sep 2008) | 2 lines
Added polish version of Woodruff, as supplied by goodoldgeorg in bug report #2098838
........
r34417 | anotherguest | 2008-09-07 18:43:03 +0200 (Sun, 07 Sep 2008) | 2 lines
Set default save path via save manager.
Fix bug in symbian-fs GetChild function.
........
r34418 | anotherguest | 2008-09-07 20:28:58 +0200 (Sun, 07 Sep 2008) | 1 line
Updated with two new variations, scumm and brokensword
........
r34419 | anotherguest | 2008-09-07 20:30:07 +0200 (Sun, 07 Sep 2008) | 1 line
Slightly updated built script. Faster?
........
r34420 | sev | 2008-09-07 20:36:40 +0200 (Sun, 07 Sep 2008) | 2 lines
Generate drascula.dat by the latest create_drascula
........
r34423 | anotherguest | 2008-09-07 21:19:45 +0200 (Sun, 07 Sep 2008) | 2 lines
Symbian already store all paths with a trailing "\".
Quick fix waiting for proper solution
........
r34424 | fingolfin | 2008-09-07 23:30:55 +0200 (Sun, 07 Sep 2008) | 1 line
Added new OSystem method addSysArchivesToSearchSet() [better name pending, suggestions welcome]
........
r34425 | fingolfin | 2008-09-07 23:38:53 +0200 (Sun, 07 Sep 2008) | 1 line
Comment out some #defines in skydefs.h as they conflict with other headers (esp. T2 conflicts with some template defs)
........
r34426 | fingolfin | 2008-09-07 23:43:36 +0200 (Sun, 07 Sep 2008) | 1 line
added two FIXMEs to M4 -- somehow, adding two subdirs of CWD named 'goodstuf' and 'resource' to the list of default dirs doesn't sound very sensible to me ;)
........
r34428 | lordhoto | 2008-09-07 23:46:37 +0200 (Sun, 07 Sep 2008) | 2 lines
Moved Kyra resource code to a SearchSet/Archive based implementation, this removes dependencies on Common::File.
........
r34429 | fingolfin | 2008-09-07 23:47:01 +0200 (Sun, 07 Sep 2008) | 1 line
Allow invoking FilesystemNode::getChild on non-dir nodes, by returning an invalid node in that case
........
r34430 | fingolfin | 2008-09-07 23:47:46 +0200 (Sun, 07 Sep 2008) | 1 line
Made File::addDefaultDirectory(Recursive) ignore FSNodes which are not dirs / are invalid, instead of erroring out
........
r34431 | fingolfin | 2008-09-07 23:51:59 +0200 (Sun, 07 Sep 2008) | 1 line
oops
........
r34432 | fingolfin | 2008-09-07 23:59:25 +0200 (Sun, 07 Sep 2008) | 1 line
Add a priority param to OSystem::addSysArchivesToSearchSet (still in search for a better name ;)
........
r34433 | fingolfin | 2008-09-08 00:00:04 +0200 (Mon, 08 Sep 2008) | 1 line
Fix warning about missing virtual destructor
........
r34434 | fingolfin | 2008-09-08 00:10:58 +0200 (Mon, 08 Sep 2008) | 1 line
Replaced Engine::_gameDataPath (a String) by Engine::_gameDataDir (an FSNode); adapted code to that (by using getChild() to get subdirs, not string concatenation
........
r34435 | lordhoto | 2008-09-08 00:30:34 +0200 (Mon, 08 Sep 2008) | 1 line
Got rid of all Common::File usages in Kyra.
........
r34436 | lordhoto | 2008-09-08 00:35:13 +0200 (Mon, 08 Sep 2008) | 2 lines
- Fixed regression in Resource::unloadPakFile
- Changed priority value for OSystem::addSysArchivesToSearchSet call
........
r34437 | fingolfin | 2008-09-08 00:37:27 +0200 (Mon, 08 Sep 2008) | 1 line
Changed md5_file(FSNode) to use FSNode::openForReading
........
r34438 | lordhoto | 2008-09-08 00:41:57 +0200 (Mon, 08 Sep 2008) | 1 line
Changed priorities for search paths. (Just in case system specific data paths contain an outdated kyra.dat version)
........
r34440 | thebluegr | 2008-09-08 10:07:06 +0200 (Mon, 08 Sep 2008) | 1 line
Cleanup
........
r34441 | thebluegr | 2008-09-08 10:09:22 +0200 (Mon, 08 Sep 2008) | 1 line
Added kyra/resource_intern.* to the kyra MSVC project files
........
r34442 | thebluegr | 2008-09-08 10:26:54 +0200 (Mon, 08 Sep 2008) | 1 line
Free the current voice lookup table a bit earlier in loadGlobalResources()
........
r34443 | thebluegr | 2008-09-08 12:36:53 +0200 (Mon, 08 Sep 2008) | 1 line
Reduced calls to File::exists()
........
r34444 | fingolfin | 2008-09-08 13:11:32 +0200 (Mon, 08 Sep 2008) | 1 line
Switched File::open, File::addDefaultDirectory to use a SearchSet internally. Code is a lot shorter & simpler now, far less failing fopen calls (good for NDS and other ports); drawback: regressions :). Good bug hunting to everybody
........
r34445 | thebluegr | 2008-09-08 13:45:15 +0200 (Mon, 08 Sep 2008) | 1 line
decompiler.cpp is not used anywhere by default. Remove it to prevent a warning under MSVC that the object file is empty (since DUMP_SCRIPT is not defined by default, the whole code in this file is not used)
........
r34446 | thebluegr | 2008-09-08 13:57:49 +0200 (Mon, 08 Sep 2008) | 1 line
Changed WarnAsError to be true across all engines, in both debug and release builds
........
r34447 | thebluegr | 2008-09-08 14:38:55 +0200 (Mon, 08 Sep 2008) | 1 line
Removed some unneeded conversions from the MSVC8->MSVC7/7.1 conversion tool
........
r34448 | thebluegr | 2008-09-08 15:00:43 +0200 (Mon, 08 Sep 2008) | 5 lines
Some more unification of options:
- AdditionalIncludeDirectories is set to "../../;../../engines"
- InlineFunctionExpansion is set to "0" for debug and "2" for release builds
- DisableLanguageExtensions is set to "false" (disabling language extensions leads to some very weird errors)
- Detect64BitPortabilityProblems is set to "false", as setting it to "true" throws loads of warnings too (mainly related to strlen, when trying to store its result in an integer)
........
r34449 | thebluegr | 2008-09-08 16:00:26 +0200 (Mon, 08 Sep 2008) | 1 line
Don't use fileName both as a structure and as a function parameter
........
r34450 | peres001 | 2008-09-08 16:38:07 +0200 (Mon, 08 Sep 2008) | 1 line
Made searching the game path recursive (with the default depth of 4 levels). This is a temporary fix to make some games work, until we decide what to do with the file/directory searching.
........
r34451 | lordhoto | 2008-09-08 20:48:39 +0200 (Mon, 08 Sep 2008) | 2 lines
Fixed LoL file loading regression.
........
r34452 | lordhoto | 2008-09-08 20:55:29 +0200 (Mon, 08 Sep 2008) | 2 lines
Made some filenames uppercase for consistency.
........
r34453 | anotherguest | 2008-09-08 23:54:04 +0200 (Mon, 08 Sep 2008) | 2 lines
Updated/Fixed Symbian Filesystem handling.
Does not store ending backslash on path, and will list any sub folder properly, by adding '\' when needed.
........
r34454 | athrxx | 2008-09-08 23:57:38 +0200 (Mon, 08 Sep 2008) | 1 line
HOF: msvc8 compile fix (ARRAYSIZE used with run-time allocated array)
........
r34456 | peres001 | 2008-09-09 01:24:20 +0200 (Tue, 09 Sep 2008) | 1 line
Documented commit 34450 (game path searched recursively).
........
r34457 | thebluegr | 2008-09-09 08:47:41 +0200 (Tue, 09 Sep 2008) | 1 line
Fix for bug #2101083 - "ANY - MSVC71 compilation fails due to warnings-as-errors"
........
r34458 | thebluegr | 2008-09-09 09:05:47 +0200 (Tue, 09 Sep 2008) | 1 line
Committed patch #2100962 - "Saga engine reduced memory usage"
........
r34460 | thebluegr | 2008-09-09 13:20:34 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup. Simplified converse()
........
r34462 | thebluegr | 2008-09-09 14:57:12 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup
........
r34463 | thebluegr | 2008-09-09 14:57:57 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup of exitRoom()
........
r34464 | thebluegr | 2008-09-09 17:59:06 +0200 (Tue, 09 Sep 2008) | 4 lines
- Cleanup and simplification
- Moved several simple animations out of animation.cpp
- Moved some animations with talk sequences inside drascula.dat
- A new version of drascula.dat is needed (will be uploaded shortly)
........
r34465 | thebluegr | 2008-09-09 17:59:52 +0200 (Tue, 09 Sep 2008) | 1 line
New version of the create_drascula tool
........
r34466 | thebluegr | 2008-09-09 18:00:28 +0200 (Tue, 09 Sep 2008) | 1 line
New version of drascula.dat
........
r34467 | lordhoto | 2008-09-09 20:09:46 +0200 (Tue, 09 Sep 2008) | 2 lines
Changed static resource code to use Streams instead of operating on buffers.
........
r34468 | thebluegr | 2008-09-10 08:57:32 +0200 (Wed, 10 Sep 2008) | 1 line
Fix in the Igor engine for bug #2101083 - "ANY - MSVC71 compilation fails due to warnings-as-errors"
........
r34469 | thebluegr | 2008-09-10 08:59:55 +0200 (Wed, 10 Sep 2008) | 1 line
Fix for bug #2102828 - "AGOS - compilation error, uninitialized variable"
........
r34472 | thebluegr | 2008-09-10 10:25:12 +0200 (Wed, 10 Sep 2008) | 1 line
Reduced game memory usage by about 400KB by only loading the current language strings, not all strings
........
r34474 | fingolfin | 2008-09-10 11:20:38 +0200 (Wed, 10 Sep 2008) | 1 line
Small fix to help with compile problems on Amiga
........
r34479 | thebluegr | 2008-09-10 14:03:42 +0200 (Wed, 10 Sep 2008) | 1 line
Merged all the methods to assign and set default palettes
........
r34480 | thebluegr | 2008-09-10 15:06:40 +0200 (Wed, 10 Sep 2008) | 1 line
Removed the unused variable changeColor
........
r34481 | lordhoto | 2008-09-10 20:01:02 +0200 (Wed, 10 Sep 2008) | 2 lines
Cleanup.
........
r34483 | vinterstum | 2008-09-10 21:46:08 +0200 (Wed, 10 Sep 2008) | 1 line
Merged up iPhone backend changes from 0.12 to trunk
........
r34484 | lordhoto | 2008-09-10 22:47:58 +0200 (Wed, 10 Sep 2008) | 2 lines
Cleanup.
........
r34485 | fingolfin | 2008-09-11 11:25:13 +0200 (Thu, 11 Sep 2008) | 1 line
Simplify check for a slash in the string *g*
........
r34486 | fingolfin | 2008-09-11 11:26:27 +0200 (Thu, 11 Sep 2008) | 1 line
Added detection for 4-language floppy version of DW (see report on forum post 39703)
........
r34487 | fingolfin | 2008-09-11 11:28:14 +0200 (Thu, 11 Sep 2008) | 1 line
Remove obsolete note about fopen
........
r34488 | thebluegr | 2008-09-11 11:31:45 +0200 (Thu, 11 Sep 2008) | 5 lines
- The game's cursor is now handled via ScummVM's cursor manager, instead of the game itself (this means that there might be regressions where the cursor is visible when it shouldn't be)
- Removed the textSurface pointer, which was used in the Spanish version. Non-Spanish versions of the game hold the font data in the tableSurface buffer (which contains picture 96). The font data for Spanish versions is in picture 974. Now both versions load their font data from the tableSurface buffer
- hay_que_load -> loadedDifferentChapter
- Merged withoutVerb() and selectVerb()
This is a big change, it might lead to regressions!
........
r34489 | thebluegr | 2008-09-11 11:33:15 +0200 (Thu, 11 Sep 2008) | 1 line
Fixed the hotspot for the crosshair cursor
........
r34490 | thebluegr | 2008-09-11 11:37:42 +0200 (Thu, 11 Sep 2008) | 1 line
Cleanup
........
r34491 | thebluegr | 2008-09-11 14:04:45 +0200 (Thu, 11 Sep 2008) | 1 line
Code optimizations from Fingolfin
........
r34492 | peres001 | 2008-09-11 15:24:01 +0200 (Thu, 11 Sep 2008) | 1 line
Added first version of the SearchManager, as it is presented in patch tracker item 2093502.
........
r34493 | thebluegr | 2008-09-11 16:49:04 +0200 (Thu, 11 Sep 2008) | 5 lines
- Merged openDoor() and closeDoor()
- Cleaned up updateDoor()
- Bugfixes to exitRoom() and gotoObject()
- Moved cursor-related functions to interface.cpp
- alapuertakeva -> roomExits
........
r34494 | thebluegr | 2008-09-11 17:35:56 +0200 (Thu, 11 Sep 2008) | 1 line
Cleanup
........
r34495 | lordhoto | 2008-09-11 21:47:45 +0200 (Thu, 11 Sep 2008) | 2 lines
Committed my patch #2105593 "Launcher/MetaEngine: Finnished removeSaveState".
........
r34496 | lordhoto | 2008-09-11 22:20:02 +0200 (Thu, 11 Sep 2008) | 4 lines
- Moved delete confirm dialog to SaveLoadChooser, allows the user to check which save he was trying to delete
- Cleaned up the SaveLoadChooser / Launcher code
-> Should reduce memory usage a little bit
........
r34497 | lordhoto | 2008-09-11 22:34:46 +0200 (Thu, 11 Sep 2008) | 2 lines
Little more cleanup.
........
r34498 | anotherguest | 2008-09-11 23:32:40 +0200 (Thu, 11 Sep 2008) | 3 lines
Added SymbianStream.h for SymbianStdioStream definition
Renamed Symbian stream implementation to
SymbianStdioStream instead of StdioStream.
........
r34501 | Kirben | 2008-09-12 03:28:28 +0200 (Fri, 12 Sep 2008) | 1 line
Fix compiling under mingw, when using latest mingw-runtime (3.15).
........
r34502 | lordhoto | 2008-09-12 14:25:56 +0200 (Fri, 12 Sep 2008) | 2 lines
Fixed slot 0 savefile name in Kyra3. (Now using 'New game' instead of 'German')
........
r34503 | thebluegr | 2008-09-12 14:54:16 +0200 (Fri, 12 Sep 2008) | 5 lines
- Moved more animation data inside drascula.dat
- Merged copyRect and copyRectClip
- Added enums for all the possible character directions and removed duplicate directions
- Extended the talk sequence commands a bit
- Removed unnecessary buffer faceBuffer and the unneeded casts between byte * and char * that were used
........
r34504 | thebluegr | 2008-09-12 14:54:47 +0200 (Fri, 12 Sep 2008) | 1 line
New version of the create_drascula tool
........
r34505 | thebluegr | 2008-09-12 14:55:25 +0200 (Fri, 12 Sep 2008) | 1 line
New version of drascula.dat
........
r34508 | Kirben | 2008-09-13 02:33:40 +0200 (Sat, 13 Sep 2008) | 1 line
Add missing targets.
........
r34511 | anotherguest | 2008-09-13 10:34:38 +0200 (Sat, 13 Sep 2008) | 1 line
Fixed drascula dat path and version nr.
........
r34512 | anotherguest | 2008-09-13 10:35:38 +0200 (Sat, 13 Sep 2008) | 1 line
Fixed rev nr. 130 will give wrong ver. in installation.
........
r34513 | eriktorbjorn | 2008-09-13 17:23:23 +0200 (Sat, 13 Sep 2008) | 2 lines
Indentation.
........
r34514 | fingolfin | 2008-09-13 18:51:46 +0200 (Sat, 13 Sep 2008) | 1 line
Big patch changing the signature of various Stream methods (some ports may need to be slightly tweaked to fix overloading errors/warnings)
........
r34515 | sev | 2008-09-13 19:41:42 +0200 (Sat, 13 Sep 2008) | 2 lines
Portability fixes.
........
r34516 | fingolfin | 2008-09-13 22:04:19 +0200 (Sat, 13 Sep 2008) | 1 line
SCUMM: Merged class BaseChunk & Chunk; got rid of MemoryChunk
........
r34517 | fingolfin | 2008-09-13 22:22:52 +0200 (Sat, 13 Sep 2008) | 1 line
SCUMM: Merged class Chunk & FileChunk
........
r34518 | fingolfin | 2008-09-14 00:41:30 +0200 (Sun, 14 Sep 2008) | 1 line
SCUMM: Got rid of class Chunk
........
r34520 | lordhoto | 2008-09-14 16:01:24 +0200 (Sun, 14 Sep 2008) | 2 lines
Rename save slots in KyraMetaEngine::removeSaveState, so it matches behavior in GUI_v2::deleteMenu at least a little bit more.
........
r34521 | lordhoto | 2008-09-14 16:08:14 +0200 (Sun, 14 Sep 2008) | 2 lines
Added a hack in KyraMetaEngine::listSaves to prevent slot 0 from being listed. Check comment for additional information.
........
r34522 | lordhoto | 2008-09-14 16:58:37 +0200 (Sun, 14 Sep 2008) | 2 lines
Only setup 'cdaudio' config default for FM-Towns/PC98.
........
r34523 | lordhoto | 2008-09-14 17:35:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Fixed regression introduced with r34522. (Now games without 'cdaudio' config value set should startup again).
........
r34524 | lordhoto | 2008-09-14 17:36:16 +0200 (Sun, 14 Sep 2008) | 2 lines
Implemented opcode 151: o1_resetMaskRegion
........
r34526 | thebluegr | 2008-09-14 18:21:31 +0200 (Sun, 14 Sep 2008) | 1 line
Fix for bug #2110375 - "DRASCULA: Mouse visible in screen saver", a regression from moving mouse handling to OSystem
........
r34527 | lordhoto | 2008-09-14 18:29:14 +0200 (Sun, 14 Sep 2008) | 2 lines
Fixed thumbnail creation / loading in kyra.
........
r34528 | lordhoto | 2008-09-14 18:48:20 +0200 (Sun, 14 Sep 2008) | 2 lines
Typo.
........
r34529 | thebluegr | 2008-09-14 20:00:06 +0200 (Sun, 14 Sep 2008) | 1 line
Updated MSVC project files for the SCUMM engine - removed smush/chunk.*
........
r34530 | lordhoto | 2008-09-14 20:19:22 +0200 (Sun, 14 Sep 2008) | 2 lines
Committed patch by [md5] from bug tracker item #2100790 "GUI:Clicking "Load" when no games are added triggers a crash".
........
r34531 | thebluegr | 2008-09-14 20:30:08 +0200 (Sun, 14 Sep 2008) | 1 line
Slight cleanup of centerText()
........
r34532 | lordhoto | 2008-09-14 20:59:43 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix for bug #2089275: "GUI: Returning to launcher may trigger an error".
........
r34533 | lordhoto | 2008-09-14 21:05:05 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix potentional bug in Screen::setResolution.
........
r34534 | lordhoto | 2008-09-14 21:16:08 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix for bug #2090879 "GUI: Launcher 'Load' dialog should preserve save slot index".
........
r34535 | lordhoto | 2008-09-14 21:48:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Added autosave support in Kyra.
........
r34536 | lordhoto | 2008-09-14 22:01:01 +0200 (Sun, 14 Sep 2008) | 2 lines
Changed message when trying to open the load dialog for games not supporting direct loading.
........
r34537 | lordhoto | 2008-09-14 22:42:50 +0200 (Sun, 14 Sep 2008) | 2 lines
Added ScummVM logo to GMM.
........
r34538 | lordhoto | 2008-09-14 22:52:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Minor improvement for GMM layout.
........
r34539 | lordhoto | 2008-09-14 23:00:24 +0200 (Sun, 14 Sep 2008) | 3 lines
- Added thumbnail support to launcher load dialog.
- Adopted KYRA to support displaying thumbnails in load dialog (SCUMM engine has yet to follow)
........
r34540 | lordhoto | 2008-09-14 23:13:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Added thumbnail support for launcher to SCUMM engine.
........
r34541 | fingolfin | 2008-09-14 23:26:59 +0200 (Sun, 14 Sep 2008) | 1 line
Fixed a typo & clarified a comment
........
r34542 | fingolfin | 2008-09-14 23:32:45 +0200 (Sun, 14 Sep 2008) | 1 line
Compilation fix for NDS
........
r34543 | lordhoto | 2008-09-14 23:34:49 +0200 (Sun, 14 Sep 2008) | 2 lines
Little cleanup.
........
r34544 | fingolfin | 2008-09-14 23:39:45 +0200 (Sun, 14 Sep 2008) | 1 line
Changed VPATH to vpath, to allow building NDS port in parallel to another port (for the records, this patch went to Neil in January, and he didn't complain)
........
r34545 | lordhoto | 2008-09-14 23:41:27 +0200 (Sun, 14 Sep 2008) | 2 lines
Cleanup.
........
r34546 | fingolfin | 2008-09-15 00:12:59 +0200 (Mon, 15 Sep 2008) | 1 line
Another NDS compilation fix, plus a warning fix
........
r34547 | fingolfin | 2008-09-15 00:15:13 +0200 (Mon, 15 Sep 2008) | 1 line
NDS: Replaced -I- by modern -iquote
........
r34548 | fingolfin | 2008-09-15 00:24:35 +0200 (Mon, 15 Sep 2008) | 1 line
DS: Removed legacy GCC 2.x build code (NDS/DevKitPro uses GCC 3 or newer anyway); thinned down INCLUDES some more; added a FIXME to the elf->bin rule
........
r34549 | wjpalenstijn | 2008-09-15 00:28:53 +0200 (Mon, 15 Sep 2008) | 6 lines
Big patch changing semantics of ReadStream::eos():
eos() now only returns true _after_ trying to read past the end of the stream.
This has a large potential for regressions. Please test!
........
r34550 | fingolfin | 2008-09-15 00:44:49 +0200 (Mon, 15 Sep 2008) | 1 line
DS: Some more compile fixes (prope solution would of course be to overload ::openForReading & ::openForWriting)
........
r34551 | lordhoto | 2008-09-15 01:14:38 +0200 (Mon, 15 Sep 2008) | 2 lines
Fixed regression introduced with latest stream changes (it seems compressed savefiles ioFailed never returned true when only eos was set).
........
r34552 | wjpalenstijn | 2008-09-15 08:51:15 +0200 (Mon, 15 Sep 2008) | 1 line
fix listSaveGames
........
r34553 | wjpalenstijn | 2008-09-15 08:52:00 +0200 (Mon, 15 Sep 2008) | 1 line
replace ioFailed by err
........
r34554 | thebluegr | 2008-09-15 11:17:18 +0200 (Mon, 15 Sep 2008) | 1 line
Proper check for eos(), after the latest changes to OSystem
........
r34555 | fingolfin | 2008-09-15 12:05:36 +0200 (Mon, 15 Sep 2008) | 1 line
Fix SubReadStream by initing _eos to false in the constructor (spotted thanks to our unit tests)
........
r34556 | fingolfin | 2008-09-15 14:37:18 +0200 (Mon, 15 Sep 2008) | 1 line
Corrected and shortened some file opening related warnings
........
r34557 | Kirben | 2008-09-15 14:37:24 +0200 (Mon, 15 Sep 2008) | 1 line
Replace ioFailed by err.
........
r34558 | thebluegr | 2008-09-15 15:37:28 +0200 (Mon, 15 Sep 2008) | 2 lines
Rewrote the very confusing centerText() function into something that makes more sense, and matches the way that the original printed text on screen (in most cases)
Fixes bugs #2102657 - "DRASCULA: Crash when talking to the piano player" and #2111820 - "DRASCULA: Dialog texts too long"
........
r34559 | thebluegr | 2008-09-15 15:45:10 +0200 (Mon, 15 Sep 2008) | 1 line
Fixed the phrase told by the protagonist when he talks to the blind man the second time
........
r34560 | thebluegr | 2008-09-15 16:17:51 +0200 (Mon, 15 Sep 2008) | 1 line
Remove a workaround in textFitsCentered(). The blind man's dialog is a bit better placed now
........
r34561 | thebluegr | 2008-09-15 16:35:11 +0200 (Mon, 15 Sep 2008) | 1 line
Show the blind man's dialog text at a bit better place
........
r34562 | wjpalenstijn | 2008-09-15 21:19:30 +0200 (Mon, 15 Sep 2008) | 1 line
fix eos() behaviour for CompressedInSaveFile
........
r34563 | wjpalenstijn | 2008-09-15 21:34:06 +0200 (Mon, 15 Sep 2008) | 1 line
also check for premature end-of-stream when loading
........
r34566 | fingolfin | 2008-09-15 23:55:50 +0200 (Mon, 15 Sep 2008) | 1 line
Turned compressed savefile wrapper into a generic stream wrapper
........
r34567 | fingolfin | 2008-09-16 00:37:45 +0200 (Tue, 16 Sep 2008) | 1 line
Fixed compiler warnings
........
r34568 | fingolfin | 2008-09-16 00:43:20 +0200 (Tue, 16 Sep 2008) | 1 line
DS: Backported 0.12 changes to trunk
........
r34569 | thebluegr | 2008-09-16 09:16:26 +0200 (Tue, 16 Sep 2008) | 2 lines
- Fixed centerText() to print text at the correct height
- Removed some duplicate code
........
r34571 | thebluegr | 2008-09-16 10:10:08 +0200 (Tue, 16 Sep 2008) | 1 line
Added a workaround to skip the silence in the beginning and end of file 3.als. Fixes bug #2111815 - "DRASCULA: Voice delayed"
........
r34572 | thebluegr | 2008-09-16 10:12:13 +0200 (Tue, 16 Sep 2008) | 1 line
Assign _lang to the appropriate enum values
........
r34573 | thebluegr | 2008-09-16 10:24:42 +0200 (Tue, 16 Sep 2008) | 1 line
Removed the confirmation speech when a game is saved - it's "99.als" instead of "s99.als", but the main problem is that it's not translated in the English version and it's in Spanish (plus it's creepy and annoying...)
........
r34574 | thebluegr | 2008-09-16 12:44:07 +0200 (Tue, 16 Sep 2008) | 1 line
Cleaned up and fixed the cutscene with Von Braun's story. Fixes bugs #2111804 - "DRASCULA: Cut scene bugs" and #2059648 - "DRASCULA: VonBraun's song"
........
r34575 | thebluegr | 2008-09-16 12:53:57 +0200 (Tue, 16 Sep 2008) | 1 line
Fixed some glitches in the last part of Von Braun's story
........
r34576 | fingolfin | 2008-09-16 13:42:21 +0200 (Tue, 16 Sep 2008) | 1 line
Modified uncompress in common/zlib.h to return a bool, so that we don't have to #include the real zlib.h; fixed PSP backend to not run uncompress inside an assert (which would cause it to not be invoked when turning off asserts)
........
r34577 | thebluegr | 2008-09-16 13:49:40 +0200 (Tue, 16 Sep 2008) | 3 lines
- Moved some includes away from drascula.h
- Moved grr() to talk.cpp
- Removed the unnecessary parameter length from isTalkFinished()
........
r34578 | fingolfin | 2008-09-16 13:50:10 +0200 (Tue, 16 Sep 2008) | 1 line
Merged common/gzip-stream.* and common/zlib.*
........
r34579 | lordhoto | 2008-09-16 13:54:37 +0200 (Tue, 16 Sep 2008) | 2 lines
Removed assert leftover.
........
r34580 | fingolfin | 2008-09-16 13:57:45 +0200 (Tue, 16 Sep 2008) | 1 line
Fix sign warnings in unit tests
........
r34581 | lordhoto | 2008-09-16 16:10:55 +0200 (Tue, 16 Sep 2008) | 6 lines
Added "querySaveMetaInfos" to MetaEngine.
-> Allows easy addition of save state specific infos like playtime, save date atc.
-> Removed MetaEngine::loadThumbnailFromSlot, superseded by meta infos
-> Changed SCUMM / KYRA to implement the newly added functionallity
-> Removed hack in KYRAs listSavefiles, which is now handled via meta infos
........
r34582 | lordhoto | 2008-09-16 16:22:51 +0200 (Tue, 16 Sep 2008) | 2 lines
Cleanup.
........
r34583 | lordhoto | 2008-09-16 16:56:02 +0200 (Tue, 16 Sep 2008) | 2 lines
Added support for SCUMM savestates date/time and playtime info in the launcher load dialog.
........
r34584 | lordhoto | 2008-09-16 16:59:52 +0200 (Tue, 16 Sep 2008) | 2 lines
Added whitespace in playtime textfield.
........
r34585 | fingolfin | 2008-09-16 22:12:25 +0200 (Tue, 16 Sep 2008) | 1 line
Removed tons of unused 'length' variables, to silence compiler warnings
........
r34586 | fingolfin | 2008-09-17 18:31:25 +0200 (Wed, 17 Sep 2008) | 1 line
adding Info.plist to svn:ignore
........
r34587 | fingolfin | 2008-09-17 18:38:01 +0200 (Wed, 17 Sep 2008) | 1 line
DS: Removing some dead code; merged (parts of) std_cwd into GBAMPSaveFileManager::listSavefiles
........
r34588 | fingolfin | 2008-09-17 18:50:19 +0200 (Wed, 17 Sep 2008) | 1 line
Adding *.dSYM (generated by gcc on OSX these days) to svn:ignore
........
r34589 | fingolfin | 2008-09-17 19:31:29 +0200 (Wed, 17 Sep 2008) | 1 line
Moved base/game.* to engines/game.*
........
r34590 | lordhoto | 2008-09-17 19:46:55 +0200 (Wed, 17 Sep 2008) | 2 lines
Fixed bug in SaveLoadChooser reflowLayout, which prevented widgets from being properly hidden.
........
r34592 | fingolfin | 2008-09-17 20:16:06 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2112604: Update for the man page
........
r34595 | fingolfin | 2008-09-17 20:26:44 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2043093 (again - new patch): OS/2 patches for posix-fs
........
r34596 | fingolfin | 2008-09-17 20:56:13 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2060517: SCUMM: engine sets incorrect talkspeed value
........
r34597 | fingolfin | 2008-09-17 20:56:54 +0200 (Wed, 17 Sep 2008) | 1 line
Added some noteworthy improvements due to Chris Page & GSoC 2008
........
r34598 | fingolfin | 2008-09-17 20:59:09 +0200 (Wed, 17 Sep 2008) | 1 line
Simplified & fixed SearchManager
........
r34599 | fingolfin | 2008-09-18 10:19:00 +0200 (Thu, 18 Sep 2008) | 1 line
Added 'native' implementations for FSDirectory::matchPattern & SearchSet::getAllNames (untested)
........
r34602 | thebluegr | 2008-09-19 12:25:40 +0200 (Fri, 19 Sep 2008) | 1 line
Updated MSVC project files with the latest changes (moved base/game.* to engines/game.*)
........
r34603 | thebluegr | 2008-09-19 15:58:09 +0200 (Fri, 19 Sep 2008) | 1 line
Changed tinsel's volume range (0-127) to match ScummVM's (0-255)
........
svn-id: r34606
Diffstat (limited to 'engines')
333 files changed, 12970 insertions, 8254 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 9d88dd73ef..a17bdc50cf 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -25,7 +25,6 @@ #include "common/md5.h" -#include "common/events.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -61,9 +60,6 @@ void AgiEngine::processEvents() { while (_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _game.quitProgNow = true; - break; case Common::EVENT_PREDICTIVE_DIALOG: if (_predictiveDialogRunning) break; @@ -738,6 +734,8 @@ void AgiEngine::initialize() { _gfx->initVideo(); _sound->initSound(); + _lastSaveTime = 0; + _timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, NULL); _game.ver = -1; /* Don't display the conf file warning */ @@ -812,4 +810,14 @@ int AgiEngine::go() { return 0; } +void AgiEngine::syncSoundSettings() { + int soundVolumeMusic = ConfMan.getInt("music_volume"); + int soundVolumeSFX = ConfMan.getInt("music_volume"); + int soundVolumeSpeech = ConfMan.getInt("music_volume"); + + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech); +} + } // End of namespace Agi diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 9240d562af..ff2b05ace1 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -530,7 +530,6 @@ struct AgiGame { /* internal flags */ int playerControl; /**< player is in control */ - int quitProgNow; /**< quit now */ int statusLine; /**< status line on/off */ int clockEnabled; /**< clock is on/off */ int exitAllLogics; /**< break cycle after new.room */ @@ -747,6 +746,8 @@ protected: int go(); void initialize(); + uint32 _lastSaveTime; + public: AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc); virtual ~AgiEngine(); @@ -754,6 +755,8 @@ public: return _gameId; } + virtual void syncSoundSettings(); + private: int _keyQueue[KEY_QUEUE_SIZE]; diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index e0babdf926..3d29f45ea5 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -24,7 +24,6 @@ */ - #include "agi/agi.h" #include "agi/sprite.h" #include "agi/graphics.h" @@ -116,7 +115,7 @@ void AgiEngine::interpretCycle() { oldSound = getflag(fSoundOn); _game.exitAllLogics = false; - while (runLogic(0) == 0 && !_game.quitProgNow) { + while (runLogic(0) == 0 && !quit()) { _game.vars[vWordNotFound] = 0; _game.vars[vBorderTouchObj] = 0; _game.vars[vBorderCode] = 0; @@ -314,7 +313,6 @@ int AgiEngine::playGame() { setvar(vTimeDelay, 2); /* "normal" speed */ _game.gfxMode = true; - _game.quitProgNow = false; _game.clockEnabled = true; _game.lineUserInput = 22; @@ -354,10 +352,16 @@ int AgiEngine::playGame() { _game.vars[vKey] = 0; } - if (_game.quitProgNow == 0xff) - ec = errRestartGame; + // FIXME: This has been broken with the merge of the RTL GSoC project. quit() returns a boolean, and we're trying to + // check it against 0xff, which is never going to be true + //if (quit() == 0xff) + // ec = errRestartGame; + + if (shouldPerformAutoSave(_lastSaveTime)) { + saveGame(getSavegameFilename(0), "Autosave"); + } - } while (_game.quitProgNow == 0); + } while (quit() == 0); _sound->stopSound(); diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index cd6942f9c0..2b2d7e080b 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -2122,11 +2122,23 @@ public: return "Sierra AGI Engine (C) Sierra On-Line Software"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - - const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; + + const Common::ADGameDescription *fallbackDetect(const Common::FSList *fslist) const; }; +bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + + bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Agi::AGIGameDescription *gd = (const Agi::AGIGameDescription *)desc; bool res = true; @@ -2147,7 +2159,48 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common: return res; } -const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fslist) const { +SaveStateList AgiMetaEngine::listSaves(const char *target) const { + const uint32 AGIflag = MKID_BE('AGI:'); + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + char saveDesc[31]; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + uint32 type = in->readUint32BE(); + if (type == AGIflag) + in->read(saveDesc, 31); + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + delete in; + } + } + } + + return saveList; +} + +void AgiMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".%03d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + +const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSList *fslist) const { typedef Common::HashMap<Common::String, int32> IntMap; IntMap allFiles; bool matchedUsingFilenames = false; @@ -2156,7 +2209,7 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl WagFileParser wagFileParser; Common::String wagFilePath; Common::String description; - FSList fslistCurrentDir; // Only used if fslist == NULL + Common::FSList fslistCurrentDir; // Only used if fslist == NULL // // Set the defaults for gameid and extra _gameid = "agi-fanmade"; @@ -2169,8 +2222,8 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl if (path.empty()) path = "."; - FilesystemNode fsCurrentDir(path); - fsCurrentDir.getChildren(fslistCurrentDir, FilesystemNode::kListFilesOnly); + Common::FilesystemNode fsCurrentDir(path); + fsCurrentDir.getChildren(fslistCurrentDir, Common::FilesystemNode::kListFilesOnly); fslist = &fslistCurrentDir; } @@ -2185,7 +2238,7 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl g_fallbackDesc.version = 0x2917; // First grab all filenames and at the same time count the number of *.wag files - for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) { + for (Common::FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) { if (file->isDirectory()) continue; Common::String filename = file->getName(); filename.toLowercase(); diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp index dcf7d83809..656ae232ec 100644 --- a/engines/agi/loader_v3.cpp +++ b/engines/agi/loader_v3.cpp @@ -47,15 +47,15 @@ int AgiLoader_v3::detectGame() { int ec = errUnk; bool found = false; - FSList fslist; - FilesystemNode dir(ConfMan.get("path")); + Common::FSList fslist; + Common::FilesystemNode dir(ConfMan.get("path")); - if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) { + if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) { warning("AgiEngine: invalid game path '%s'", dir.getPath().c_str()); return errInvalidAGIFile; } - for (FSList::const_iterator file = fslist.begin(); + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end() && !found; ++file) { Common::String f = file->getName(); f.toLowercase(); @@ -230,8 +230,8 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) { debugC(3, kDebugLevelResources, "offset = %d", agid->offset); debugC(3, kDebugLevelResources, "x = %x %x", x[0], x[1]); error("ACK! BAD RESOURCE"); - - g_system->quit(); + + _vm->quitGame(); } agid->len = READ_LE_UINT16((uint8 *) x + 3); /* uncompressed size */ diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index 7ecedfbc8c..758bff0cb6 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -1213,11 +1213,11 @@ cmd(quit) { g_sound->stopSound(); if (p0) { - game.quitProgNow = true; + g_agi->quitGame(); } else { if (g_agi->selectionBox (" Quit the game, or continue? \n\n\n", buttons) == 0) { - game.quitProgNow = true; + g_agi->quitGame(); } } } @@ -1231,7 +1231,7 @@ cmd(restart_game) { g_agi->selectionBox(" Restart game, or continue? \n\n\n", buttons); if (sel == 0) { - game.quitProgNow = 0xff; + g_agi->quitGame(); g_agi->setflag(fRestartGame, true); g_agi->_menu->enableAll(); } @@ -1739,7 +1739,7 @@ int AgiEngine::runLogic(int n) { curLogic->cIP = curLogic->sIP; timerHack = 0; - while (ip < _game.logics[n].size && !_game.quitProgNow) { + while (ip < _game.logics[n].size && !quit()) { if (_debug.enabled) { if (_debug.steps > 0) { if (_debug.logic0 || n) { diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp index 7ba3e625bf..393057ed9c 100644 --- a/engines/agi/op_test.cpp +++ b/engines/agi/op_test.cpp @@ -24,7 +24,6 @@ */ - #include "agi/agi.h" #include "agi/keyboard.h" #include "agi/opcodes.h" @@ -232,7 +231,7 @@ int AgiEngine::testIfCode(int lognum) { uint8 p[16] = { 0 }; bool end_test = false; - while (retval && !game.quitProgNow && !end_test) { + while (retval && !quit() && !end_test) { if (_debug.enabled && (_debug.logic0 || lognum)) debugConsole(lognum, lTEST_MODE, NULL); diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp index f2301e012a..666d1b1b11 100644 --- a/engines/agi/preagi.cpp +++ b/engines/agi/preagi.cpp @@ -23,7 +23,6 @@ * */ -#include "common/events.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h index 500f98546b..d95035a073 100644 --- a/engines/agi/preagi.h +++ b/engines/agi/preagi.h @@ -73,7 +73,7 @@ public: // Keyboard int getSelection(SelectionTypes type); - int rnd(int hi) { return (_rnd->getRandomNumber(hi) + 1); } + int rnd(int hi) { return (_rnd->getRandomNumber(hi - 1) + 1); } // Text void drawStr(int row, int col, int attr, const char *buffer); diff --git a/engines/agi/preagi_common.cpp b/engines/agi/preagi_common.cpp index 5d99dfa7f9..3cd04351f7 100644 --- a/engines/agi/preagi_common.cpp +++ b/engines/agi/preagi_common.cpp @@ -23,8 +23,6 @@ * */ -#include "common/events.h" - #include "agi/preagi.h" #include "agi/font.h" #include "agi/graphics.h" @@ -122,11 +120,12 @@ void PreAgiEngine::printStrXOR(char *szMsg) { int PreAgiEngine::getSelection(SelectionTypes type) { Common::Event event; - for (;;) { + while (!quit()) { while (_eventMan->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _system->quit(); + return 0; case Common::EVENT_RBUTTONUP: return 0; case Common::EVENT_LBUTTONUP: diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp index 08f8969ca3..f643ab9cfc 100644 --- a/engines/agi/preagi_mickey.cpp +++ b/engines/agi/preagi_mickey.cpp @@ -23,7 +23,6 @@ * */ -#include "common/events.h" #include "common/savefile.h" #include "common/stream.h" @@ -343,11 +342,12 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) { drawMenu(menu, *sel0, *sel1); - for (;;) { + for(;;) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - exit(0); + return 0; case Common::EVENT_MOUSEMOVE: if (iRow < 2) { x = event.mouse.x / 8; @@ -640,8 +640,8 @@ void Mickey::playSound(ENUM_MSA_SOUND iSound) { if (iSound == IDI_MSA_SND_THEME) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->_system->quit(); case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: case Common::EVENT_KEYDOWN: @@ -932,10 +932,17 @@ bool Mickey::loadGame() { if (_vm->getSelection(kSelAnyKey) == 0) return false; } else { - if (infile->readUint32BE() != MKID_BE('MICK')) - error("Mickey::loadGame wrong save game format"); + if (infile->readUint32BE() != MKID_BE('MICK')) { + warning("Mickey::loadGame wrong save game format"); + return false; + } saveVersion = infile->readByte(); + if (saveVersion < 2) { + warning("The planet data in this save game is corrupted. Load aborted"); + return false; + } + if (saveVersion != MSA_SAVEGAME_VERSION) warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, MSA_SAVEGAME_VERSION); @@ -953,7 +960,7 @@ bool Mickey::loadGame() { _game.iPlanetXtal[i] = infile->readByte(); for(i = 0; i < IDI_MSA_MAX_PLANET; i++) - _game.iClue[i] = infile->readByte(); + _game.iClue[i] = infile->readUint16LE(); infile->read(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); @@ -1058,7 +1065,7 @@ void Mickey::saveGame() { outfile->writeByte(_game.iPlanetXtal[i]); for(i = 0; i < IDI_MSA_MAX_PLANET; i++) - outfile->writeByte(_game.iClue[i]); + outfile->writeUint16LE(_game.iClue[i]); outfile->write(_game.szAddr, IDI_MSA_MAX_BUTTON + 1); @@ -1214,7 +1221,7 @@ void Mickey::gameOver() { } waitAnyKey(); - exit(0); + _vm->quitGame(); } void Mickey::flipSwitch() { @@ -2053,8 +2060,8 @@ void Mickey::waitAnyKey(bool anim) { for (;;) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->_system->quit(); case Common::EVENT_KEYDOWN: case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: @@ -2153,7 +2160,7 @@ void Mickey::run() { intro(); // Game loop - for (;;) { + while (!_vm->quit()) { drawRoom(); if (_game.fIntro) { diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h index 8d982dc401..f29d2fbccd 100644 --- a/engines/agi/preagi_mickey.h +++ b/engines/agi/preagi_mickey.h @@ -30,7 +30,7 @@ namespace Agi { -#define MSA_SAVEGAME_VERSION 1 +#define MSA_SAVEGAME_VERSION 2 // strings #define IDS_MSA_PATH_DAT "dat/%s" @@ -637,7 +637,7 @@ const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = { {0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto {0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter {0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars - {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus + {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus }; // message offsets @@ -697,7 +697,7 @@ struct MSA_GAME { uint8 nXtals; uint8 iPlanetXtal[IDI_MSA_MAX_DAT]; - uint8 iClue[IDI_MSA_MAX_PLANET]; + uint16 iClue[IDI_MSA_MAX_PLANET]; char szAddr[IDI_MSA_MAX_BUTTON + 1]; // Flags diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp index 7502c63c6c..beff721fda 100644 --- a/engines/agi/preagi_troll.cpp +++ b/engines/agi/preagi_troll.cpp @@ -30,8 +30,6 @@ #include "graphics/cursorman.h" -#include "common/events.h" - namespace Agi { Troll::Troll(PreAgiEngine* vm) : _vm(vm) { @@ -58,11 +56,12 @@ bool Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) { drawMenu(szMenu, *iSel); - for (;;) { + while (!_vm->quit()) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->_system->quit(); + return 0; case Common::EVENT_MOUSEMOVE: y = event.mouse.y / 8; @@ -205,8 +204,8 @@ void Troll::waitAnyKeyIntro() { for (;;) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->_system->quit(); case Common::EVENT_LBUTTONUP: case Common::EVENT_KEYDOWN: return; @@ -269,7 +268,7 @@ void Troll::tutorial() { int iSel = 0; //char szTreasure[16] = {0}; - for (;;) { + while (!_vm->quit()) { _vm->clearScreen(0xFF); _vm->printStr(IDS_TRO_TUTORIAL_0); diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp index 87d13bff3d..de8839b7bc 100644 --- a/engines/agi/preagi_winnie.cpp +++ b/engines/agi/preagi_winnie.cpp @@ -29,7 +29,6 @@ #include "graphics/cursorman.h" -#include "common/events.h" #include "common/savefile.h" #include "common/stream.h" @@ -797,12 +796,12 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) { // Show the mouse cursor for the menu CursorMan.showMouse(true); - for (;;) { + while (!_vm->quit()) { while (_vm->_system->getEventManager()->pollEvent(event)) { switch(event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->_system->quit(); - break; + return; case Common::EVENT_MOUSEMOVE: x = event.mouse.x / 8; y = event.mouse.y / 8; @@ -1014,7 +1013,7 @@ phase2: if (parser(hdr.ofsDesc[iBlock] - _roomOffset, iBlock, roomdata) == IDI_WTP_PAR_BACK) goto phase1; } - for (;;) { + while (!_vm->quit()) { for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) { switch(parser(hdr.ofsBlock[iBlock] - _roomOffset, iBlock, roomdata)) { case IDI_WTP_PAR_GOTO: diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index db7bba13e4..0b308bb37b 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -91,7 +91,7 @@ int AgiEngine::saveGame(const char *fileName, const char *description) { out->writeSint16BE((int16)_game.lognum); out->writeSint16BE((int16)_game.playerControl); - out->writeSint16BE((int16)_game.quitProgNow); + out->writeSint16BE((int16)quit()); out->writeSint16BE((int16)_game.statusLine); out->writeSint16BE((int16)_game.clockEnabled); out->writeSint16BE((int16)_game.exitAllLogics); @@ -214,6 +214,9 @@ int AgiEngine::saveGame(const char *fileName, const char *description) { delete out; debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName); + + _lastSaveTime = _system->getMillis(); + return result; } @@ -281,7 +284,8 @@ int AgiEngine::loadGame(const char *fileName, bool checkId) { _game.lognum = in->readSint16BE(); _game.playerControl = in->readSint16BE(); - _game.quitProgNow = in->readSint16BE(); + if (in->readSint16BE()) + quitGame(); _game.statusLine = in->readSint16BE(); _game.clockEnabled = in->readSint16BE(); _game.exitAllLogics = in->readSint16BE(); @@ -698,13 +702,18 @@ int AgiEngine::saveGameDialog() { sprintf(fileName, "%s", getSavegameFilename(slot)); - drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp); - printText("Select a slot in which you wish to\nsave the game:", - 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR); - slot = selectSlot(); - if (slot < 0) - return errOK; + do { + drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp); + printText("Select a slot in which you wish to\nsave the game:", + 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR); + slot = selectSlot(); + if (slot == 0) + messageBox("That slot is for Autosave only."); + else if (slot < 0) + return errOK; + } + while (slot == 0); drawWindow(hp, vp + 5 * CHAR_LINES, GFX_WIDTH - hp, GFX_HEIGHT - vp - 9 * CHAR_LINES); diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index 9fe8fbf41a..3b28e75c56 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -1013,7 +1013,7 @@ bool IIgsSoundMgr::loadInstrumentHeaders(const Common::String &exePath, const II // Open the executable file and check that it has correct size file.open(exePath); - if (file.size() != exeInfo.exeSize) { + if (file.size() != (int32)exeInfo.exeSize) { debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)", exePath.c_str(), file.size(), exeInfo.exeSize); } @@ -1023,7 +1023,7 @@ bool IIgsSoundMgr::loadInstrumentHeaders(const Common::String &exePath, const II file.close(); // Check that we got enough data to be able to parse the instruments - if (data && data->size() >= (exeInfo.instSetStart + exeInfo.instSet.byteCount)) { + if (data && data->size() >= (int32)(exeInfo.instSetStart + exeInfo.instSet.byteCount)) { // Check instrument set's length (The info's saved in the executable) data->seek(exeInfo.instSetStart - 4); uint16 instSetByteCount = data->readUint16LE(); @@ -1107,14 +1107,14 @@ bool IIgsSoundMgr::loadWaveFile(const Common::String &wavePath, const IIgsExeInf } /** - * A function object (i.e. a functor) for testing if a FilesystemNode + * A function object (i.e. a functor) for testing if a Common::FilesystemNode * object's name is equal (Ignoring case) to a string or to at least * one of the strings in a list of strings. Can be used e.g. with find_if(). */ -struct fsnodeNameEqualsIgnoreCase : public Common::UnaryFunction<const FilesystemNode&, bool> { +struct fsnodeNameEqualsIgnoreCase : public Common::UnaryFunction<const Common::FilesystemNode&, bool> { fsnodeNameEqualsIgnoreCase(const Common::StringList &str) : _str(str) {} fsnodeNameEqualsIgnoreCase(const Common::String str) { _str.push_back(str); } - bool operator()(const FilesystemNode ¶m) const { + bool operator()(const Common::FilesystemNode ¶m) const { for (Common::StringList::const_iterator iter = _str.begin(); iter != _str.end(); iter++) if (param.getName().equalsIgnoreCase(*iter)) return true; @@ -1139,9 +1139,9 @@ bool SoundMgr::loadInstruments() { } // List files in the game path - FSList fslist; - FilesystemNode dir(ConfMan.get("path")); - if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) { + Common::FSList fslist; + Common::FilesystemNode dir(ConfMan.get("path")); + if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) { warning("Invalid game path (\"%s\"), not loading Apple IIGS instruments", dir.getPath().c_str()); return false; } @@ -1157,7 +1157,7 @@ bool SoundMgr::loadInstruments() { waveNames.push_back("SIERRAST"); // Search for the executable file and the wave file (i.e. check if any of the filenames match) - FSList::const_iterator exeFsnode, waveFsnode; + Common::FSList::const_iterator exeFsnode, waveFsnode; exeFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(exeNames)); waveFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(waveNames)); diff --git a/engines/agi/wagparser.h b/engines/agi/wagparser.h index 2f4003315f..827720ac85 100644 --- a/engines/agi/wagparser.h +++ b/engines/agi/wagparser.h @@ -201,7 +201,9 @@ protected: class WagFileParser { // Constants, type definitions, enumerations etc. public: - static const uint WINAGI_VERSION_LENGTH = 16; ///< WinAGI's version string's length (Always 16) + enum { + WINAGI_VERSION_LENGTH = 16 ///< WinAGI's version string's length (Always 16) + }; typedef Common::Array<WagProperty> PropertyList; ///< A type definition for an array of *.wag file properties public: diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index a9fd204d73..97d84e036c 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -97,8 +97,6 @@ AGOSEngine::AGOSEngine(OSystem *syst) _vc_get_out_of_code = 0; _gameOffsetsPtr = 0; - _quit = false; - _debugger = 0; _gameFile = 0; @@ -508,24 +506,24 @@ AGOSEngine::AGOSEngine(OSystem *syst) // Add default file directories for Acorn version of // Simon the Sorcerer 1 - File::addDefaultDirectory(_gameDataPath + "execute"); - File::addDefaultDirectory(_gameDataPath + "EXECUTE"); + File::addDefaultDirectory(_gameDataDir.getChild("execute")); + File::addDefaultDirectory(_gameDataDir.getChild("EXECUTE")); // Add default file directories for Amiga/Macintosh // verisons of Simon the Sorcerer 2 - File::addDefaultDirectory(_gameDataPath + "voices"); - File::addDefaultDirectory(_gameDataPath + "VOICES"); + File::addDefaultDirectory(_gameDataDir.getChild("voices")); + File::addDefaultDirectory(_gameDataDir.getChild("VOICES")); // Add default file directories for Amiga & Macintosh // versions of The Feeble Files - File::addDefaultDirectory(_gameDataPath + "gfx"); - File::addDefaultDirectory(_gameDataPath + "GFX"); - File::addDefaultDirectory(_gameDataPath + "movies"); - File::addDefaultDirectory(_gameDataPath + "MOVIES"); - File::addDefaultDirectory(_gameDataPath + "sfx"); - File::addDefaultDirectory(_gameDataPath + "SFX"); - File::addDefaultDirectory(_gameDataPath + "speech"); - File::addDefaultDirectory(_gameDataPath + "SPEECH"); + File::addDefaultDirectory(_gameDataDir.getChild("gfx")); + File::addDefaultDirectory(_gameDataDir.getChild("GFX")); + File::addDefaultDirectory(_gameDataDir.getChild("movies")); + File::addDefaultDirectory(_gameDataDir.getChild("MOVIES")); + File::addDefaultDirectory(_gameDataDir.getChild("sfx")); + File::addDefaultDirectory(_gameDataDir.getChild("SFX")); + File::addDefaultDirectory(_gameDataDir.getChild("speech")); + File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); syst->getEventManager()->registerRandomSource(_rnd, "agos"); } @@ -550,6 +548,7 @@ int AGOSEngine::init() { // Setup mixer _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); if ((getGameType() == GType_SIMON2 && getPlatform() == Common::kPlatformWindows) || (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) || @@ -574,7 +573,7 @@ int AGOSEngine::init() { if (ret) warning("MIDI Player init failed: \"%s\"", _midi.getErrorName (ret)); - _midi.setVolume(ConfMan.getInt("music_volume")); + _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume")); _midiEnabled = true; @@ -952,7 +951,7 @@ void AGOSEngine::pauseEngineIntern(bool pauseIt) { void AGOSEngine::pause() { pauseEngine(true); - while (_pause && !_quit) { + while (_pause && !quit()) { delay(1); if (_keyPressed.keycode == Common::KEYCODE_p) pauseEngine(false); @@ -989,7 +988,7 @@ int AGOSEngine::go() { (getFeatures() & GF_DEMO)) { int i; - while (!_quit) { + while (!quit()) { for (i = 0; i < 4; i++) { setWindowImage(3, 9902 + i); debug(0, "Displaying image %d", 9902 + i); @@ -1018,7 +1017,7 @@ int AGOSEngine::go() { runSubroutine101(); permitInput(); - while (!_quit) { + while (!quit()) { waitForInput(); handleVerbClicked(_verbHitArea); delay(100); @@ -1084,4 +1083,12 @@ uint32 AGOSEngine::getTime() const { return (uint32)time(NULL); } + +void AGOSEngine::syncSoundSettings() { + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); + _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume")); +} + } // End of namespace AGOS diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 8ad5487b35..49b4478ec7 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -269,7 +269,6 @@ protected: uint16 _marks; - bool _quit; bool _scriptVar2; bool _runScriptReturn1; bool _runScriptCondition[40]; @@ -589,6 +588,8 @@ protected: void loadSoundFile(const char *filename); + virtual void syncSoundSettings(); + int getUserFlag(Item *item, int a); int getUserFlag1(Item *item, int a); int getUserItem(Item *item, int n); diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 3e1b9b0611..f4abf19645 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -26,7 +26,6 @@ #include "common/endian.h" -#include "common/events.h" #include "common/system.h" #include "graphics/cursorman.h" @@ -151,7 +150,7 @@ void MoviePlayer::play() { startSound(); - while (_frameNum < _framesCount && !_vm->_quit) + while (_frameNum < _framesCount && !_vm->quit()) handleNextFrame(); closeFile(); @@ -279,9 +278,6 @@ void MoviePlayer::handleNextFrame() { case Common::EVENT_RBUTTONUP: _rightButtonDown = false; break; - case Common::EVENT_QUIT: - _vm->_quit = true; - break; default: break; } diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp index 26d8916ab7..12f281d0dc 100644 --- a/engines/agos/detection.cpp +++ b/engines/agos/detection.cpp @@ -27,6 +27,7 @@ #include "common/advancedDetector.h" #include "common/config-manager.h" +#include "common/savefile.h" #include "agos/agos.h" @@ -100,7 +101,7 @@ static const Common::ADParams detectionParams = { class AgosMetaEngine : public Common::AdvancedMetaEngine { public: AgosMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {} - + virtual const char *getName() const { return "AGOS"; } @@ -108,10 +109,18 @@ public: virtual const char *getCopyright() const { return "AGOS (C) Adventure Soft"; } - + + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; }; +bool AgosMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves); +} + bool AgosMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const AGOS::AGOSGameDescription *gd = (const AGOS::AGOSGameDescription *)desc; bool res = true; @@ -149,6 +158,34 @@ bool AgosMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common return res; } +SaveStateList AgosMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + Common::String saveDesc; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + saveDesc = file->c_str(); + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); + delete in; + } + } + } + + return saveList; +} + #if PLUGIN_ENABLED_DYNAMIC(AGOS) REGISTER_PLUGIN_DYNAMIC(AGOS, PLUGIN_TYPE_ENGINE, AgosMetaEngine); #else diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index 010b331cf8..4db3545594 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -142,7 +142,7 @@ bool AGOSEngine::kickoffTimeEvents() { cur_time = getTime() - _gameStoppedClock; - while ((te = _firstTimeStruct) != NULL && te->time <= cur_time && !_quit) { + while ((te = _firstTimeStruct) != NULL && te->time <= cur_time && !quit()) { result = true; _pendingDeleteTimeEvent = te; invokeTimeEvent(te); @@ -520,8 +520,8 @@ void AGOSEngine::delay(uint amount) { setBitFlag(92, false); _rightButtonDown++; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _quit = true; return; default: break; @@ -544,7 +544,7 @@ void AGOSEngine::delay(uint amount) { _system->delayMillis(this_delay); cur = _system->getMillis(); - } while (cur < start + amount && !_quit); + } while (cur < start + amount && !quit()); } void AGOSEngine::timer_callback() { diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 9a3962ea21..25a4b919f4 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -1286,7 +1286,7 @@ void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vga_res) { if (getGameType() == GType_WW && (mode == 6 || mode == 8 || mode == 9)) { setWindowImage(mode, vga_res); } else { - while (_copyScnFlag && !_quit) + while (_copyScnFlag && !quit()) delay(1); setWindowImage(mode, vga_res); diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index 6f4cd09947..4327c2878d 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -123,7 +123,7 @@ void AGOSEngine::setup_cond_c_helper() { clearName(); _lastNameOn = last; - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = 0; _leftButtonDown = 0; @@ -145,7 +145,7 @@ void AGOSEngine::setup_cond_c_helper() { } delay(100); - } while ((_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0) && !_quit); + } while ((_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0) && !quit()); if (_lastHitArea == NULL) { } else if (_lastHitArea->id == 0x7FFB) { @@ -189,12 +189,12 @@ void AGOSEngine::waitForInput() { resetVerbs(); } - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; _dragAccept = 1; - while (!_quit) { + while (!quit()) { if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && _keyPressed.keycode == Common::KEYCODE_F10) displayBoxStars(); @@ -563,16 +563,18 @@ bool AGOSEngine::processSpecialKeys() { case Common::KEYCODE_PLUS: case Common::KEYCODE_KP_PLUS: if (_midiEnabled) { - _midi.setVolume(_midi.getVolume() + 16); + _midi.setVolume(_midi.getMusicVolume() + 16, _midi.getSFXVolume() + 16); } - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16); + ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16); + syncSoundSettings(); break; case Common::KEYCODE_MINUS: case Common::KEYCODE_KP_MINUS: if (_midiEnabled) { - _midi.setVolume(_midi.getVolume() - 16); + _midi.setVolume(_midi.getMusicVolume() - 16, _midi.getSFXVolume() - 16); } - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16); + ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16); + syncSoundSettings(); break; case Common::KEYCODE_m: _musicPaused ^= 1; diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp index 891e9bde95..fd0e4eaa9d 100644 --- a/engines/agos/midi.cpp +++ b/engines/agos/midi.cpp @@ -49,7 +49,9 @@ MidiPlayer::MidiPlayer() { _enable_sfx = true; _current = 0; - _masterVolume = 255; + _musicVolume = 255; + _sfxVolume = 255; + resetVolumeTable(); _paused = false; @@ -104,10 +106,13 @@ void MidiPlayer::send(uint32 b) { byte channel = (byte)(b & 0x0F); if ((b & 0xFFF0) == 0x07B0) { - // Adjust volume changes by master volume. + // Adjust volume changes by master music and master sfx volume. byte volume = (byte)((b >> 16) & 0x7F); _current->volume[channel] = volume; - volume = volume * _masterVolume / 255; + if (_current == &_sfx) + volume = volume * _sfxVolume / 255; + else if (_current == &_music) + volume = volume * _musicVolume / 255; b = (b & 0xFF00FFFF) | (volume << 16); } else if ((b & 0xF0) == 0xC0 && _map_mt32_to_gm) { b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8); @@ -133,8 +138,12 @@ void MidiPlayer::send(uint32 b) { if (!_current->channel[channel]) _current->channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); if (_current->channel[channel]) { - if (channel == 9) - _current->channel[9]->volume(_current->volume[9] * _masterVolume / 255); + if (channel == 9) { + if (_current == &_sfx) + _current->channel[9]->volume(_current->volume[9] * _sfxVolume / 255); + else if (_current == &_music) + _current->channel[9]->volume(_current->volume[9] * _musicVolume / 255); + } _current->channel[channel]->send(b); if ((b & 0xFFF0) == 0x79B0) { // We have received a "Reset All Controllers" message @@ -143,7 +152,10 @@ void MidiPlayer::send(uint32 b) { // consistent behaviour, explicitly set the volume to // what we think it should be. - _current->channel[channel]->volume(_current->volume[channel] * _masterVolume / 255); + if (_current == &_sfx) + _current->channel[channel]->volume(_current->volume[channel] * _sfxVolume / 255); + else if (_current == &_music) + _current->channel[channel]->volume(_current->volume[channel] * _musicVolume / 255); } } } @@ -255,30 +267,36 @@ void MidiPlayer::pause(bool b) { Common::StackLock lock(_mutex); for (int i = 0; i < 16; ++i) { if (_music.channel[i]) - _music.channel[i]->volume(_paused ? 0 : (_music.volume[i] * _masterVolume / 255)); + _music.channel[i]->volume(_paused ? 0 : (_music.volume[i] * _musicVolume / 255)); if (_sfx.channel[i]) - _sfx.channel[i]->volume(_paused ? 0 : (_sfx.volume[i] * _masterVolume / 255)); + _sfx.channel[i]->volume(_paused ? 0 : (_sfx.volume[i] * _sfxVolume / 255)); } } -void MidiPlayer::setVolume(int volume) { - if (volume < 0) - volume = 0; - else if (volume > 255) - volume = 255; - - if (_masterVolume == volume) +void MidiPlayer::setVolume(int musicVol, int sfxVol) { + if (musicVol < 0) + musicVol = 0; + else if (musicVol > 255) + musicVol = 255; + if (sfxVol < 0) + sfxVol = 0; + else if (sfxVol > 255) + sfxVol = 255; + + if (_musicVolume == musicVol && _sfxVolume == sfxVol) return; - _masterVolume = volume; + + _musicVolume = musicVol; + _sfxVolume = sfxVol; // Now tell all the channels this. Common::StackLock lock(_mutex); if (_driver && !_paused) { for (int i = 0; i < 16; ++i) { if (_music.channel[i]) - _music.channel[i]->volume(_music.volume[i] * _masterVolume / 255); + _music.channel[i]->volume(_music.volume[i] * _musicVolume / 255); if (_sfx.channel[i]) - _sfx.channel[i]->volume(_sfx.volume[i] * _masterVolume / 255); + _sfx.channel[i]->volume(_sfx.volume[i] * _sfxVolume / 255); } } } @@ -354,7 +372,7 @@ void MidiPlayer::resetVolumeTable() { for (i = 0; i < 16; ++i) { _music.volume[i] = _sfx.volume[i] = 127; if (_driver) - _driver->send(((_masterVolume >> 1) << 16) | 0x7B0 | i); + _driver->send(((_musicVolume >> 1) << 16) | 0x7B0 | i); } } diff --git a/engines/agos/midi.h b/engines/agos/midi.h index 2994c49bb6..c004230e5b 100644 --- a/engines/agos/midi.h +++ b/engines/agos/midi.h @@ -68,6 +68,8 @@ protected: // These are maintained for both music and SFX byte _masterVolume; // 0-255 + byte _musicVolume; + byte _sfxVolume; bool _paused; // These are only used for music. @@ -103,8 +105,9 @@ public: void stop(); void pause(bool b); - int getVolume() { return _masterVolume; } - void setVolume(int volume); + int getMusicVolume() { return _musicVolume; } + int getSFXVolume() { return _sfxVolume; } + void setVolume(int musicVol, int sfxVol); void setDriver(MidiDriver *md); public: diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp index 2d2feb7b9e..c174362e7c 100644 --- a/engines/agos/oracle.cpp +++ b/engines/agos/oracle.cpp @@ -459,7 +459,7 @@ void AGOSEngine_Feeble::saveUserGame(int slot) { } windowPutChar(window, 0x7f); - while (!_quit) { + while (!quit()) { _keyPressed.reset(); delay(1); diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp index 4aca390f3b..cd0d8e7ef6 100644 --- a/engines/agos/res.cpp +++ b/engines/agos/res.cpp @@ -74,8 +74,7 @@ void AGOSEngine::decompressData(const char *srcName, byte *dst, uint32 offset, u error("decompressData: Read failed"); unsigned long decompressedSize = dstSize; - int result = Common::uncompress(dst, &decompressedSize, srcBuffer, srcSize); - if (result != Common::ZLIB_OK) + if (!Common::uncompress(dst, &decompressedSize, srcBuffer, srcSize)) error("decompressData: Zlib uncompress error"); free(srcBuffer); } else { diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 9779630d47..c1a4e91c95 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -244,7 +244,7 @@ int16 AGOSEngine::matchSaveGame(const char *name, uint16 max) { void AGOSEngine::userGame(bool load) { WindowBlock *window = _windowArray[4]; const char *message1; - int i, numSaveGames; + int i = 0, numSaveGames; char *name; char buf[8]; @@ -279,11 +279,11 @@ restart: name = buf; _saveGameNameLen = 0; - while (!_quit) { + while (!quit()) { windowPutChar(window, 128); _keyPressed.reset(); - while (!_quit) { + while (!quit()) { delay(10); if (_keyPressed.ascii && _keyPressed.ascii < 128) { i = _keyPressed.ascii; @@ -443,7 +443,7 @@ void AGOSEngine_Elvira2::userGame(bool load) { name = buf + 192; - while (!_quit) { + while (!quit()) { windowPutChar(window, 128); _saveLoadEdit = true; @@ -516,7 +516,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) { _keyPressed.reset(); - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; @@ -526,7 +526,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) { return _keyPressed.ascii; } delay(10); - } while (_lastHitArea3 == 0 && !_quit); + } while (_lastHitArea3 == 0 && !quit()); ha = _lastHitArea; if (ha == NULL || ha->id < 200) { @@ -708,7 +708,7 @@ restart:; _saveGameNameLen++; } - while (!_quit) { + while (!quit()) { windowPutChar(window, 127); _saveLoadEdit = true; @@ -787,7 +787,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) { _keyPressed.reset(); - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; @@ -797,7 +797,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) { return _keyPressed.ascii; } delay(10); - } while (_lastHitArea3 == 0 && !_quit); + } while (_lastHitArea3 == 0 && !quit()); ha = _lastHitArea; if (ha == NULL || ha->id < 205) { @@ -1056,7 +1056,7 @@ bool AGOSEngine::loadGame(const char *filename, bool restartMode) { writeVariable(i, f->readUint16BE()); } - if (f->ioFailed()) { + if (f->err()) { error("load failed"); } @@ -1140,7 +1140,7 @@ bool AGOSEngine::saveGame(uint slot, const char *caption) { } f->finalize(); - bool result = !f->ioFailed(); + bool result = !f->err(); delete f; _lockWord &= ~0x100; @@ -1331,7 +1331,7 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) { _superRoomNumber = f->readUint16BE(); } - if (f->ioFailed()) { + if (f->err()) { error("load failed"); } @@ -1503,7 +1503,7 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { } f->finalize(); - bool result = !f->ioFailed(); + bool result = !f->err(); delete f; _lockWord &= ~0x100; diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp index fa132ec26f..39c172be62 100644 --- a/engines/agos/script.cpp +++ b/engines/agos/script.cpp @@ -410,7 +410,7 @@ void AGOSEngine::o_msg() { void AGOSEngine::o_end() { // 68: exit interpreter - _quit = true; + quitGame(); } void AGOSEngine::o_done() { @@ -965,7 +965,7 @@ void AGOSEngine::writeVariable(uint16 variable, uint16 contents) { int AGOSEngine::runScript() { bool flag; - if (_quit) + if (quit()) return 1; do { @@ -1010,9 +1010,9 @@ int AGOSEngine::runScript() { error("Invalid opcode '%d' encountered", _opcode); executeOpcode(_opcode); - } while (getScriptCondition() != flag && !getScriptReturn() && !_quit); + } while (getScriptCondition() != flag && !getScriptReturn() && !quit()); - return (_quit) ? 1 : getScriptReturn(); + return (quit()) ? 1 : getScriptReturn(); } Child *nextSub(Child *sub, int16 key) { @@ -1066,7 +1066,7 @@ void AGOSEngine::waitForSync(uint a) { _exitCutscene = false; _rightButtonDown = false; - while (_vgaWaitFor != 0 && !_quit) { + while (_vgaWaitFor != 0 && !quit()) { if (_rightButtonDown) { if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) { skipSpeech(); diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp index 9b572e347b..8705755df6 100644 --- a/engines/agos/script_e1.cpp +++ b/engines/agos/script_e1.cpp @@ -24,7 +24,6 @@ */ - #include "agos/agos.h" #include "agos/vga.h" @@ -565,7 +564,7 @@ void AGOSEngine_Elvira1::oe1_look() { lobjFunc(l, "You can see "); /* Show objects */ } if (r && (r->flags & 4) && levelOf(i) < 10000) { - _quit = true; + quitGame(); } } @@ -944,7 +943,7 @@ restart: windowPutChar(window, *message2); if (confirmYesOrNo(120, 62) == 0x7FFF) { - _quit = true; + quitGame(); } else { goto restart; } @@ -1053,11 +1052,11 @@ uint AGOSEngine::confirmYesOrNo(uint16 x, uint16 y) { ha->priority = 999; ha->window = 0; - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; - while (!_quit) { + while (!quit()) { if (_lastHitArea3 != 0) break; delay(1); @@ -1102,11 +1101,11 @@ uint AGOSEngine::continueOrQuit() { ha->priority = 999; ha->window = 0; - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; - while (!_quit) { + while (!quit()) { if (_lastHitArea3 != 0) break; delay(1); diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp index 6f6db8efb4..05e457579d 100644 --- a/engines/agos/script_e2.cpp +++ b/engines/agos/script_e2.cpp @@ -370,11 +370,11 @@ void AGOSEngine_Elvira2::oe2_pauseGame() { uint32 pauseTime = getTime(); haltAnimation(); - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; - while (!_quit) { + while (!quit()) { if (processSpecialKeys() != 0 || _lastHitArea3 != 0) break; delay(1); diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index 6183a3fb20..d07f682937 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -24,7 +24,6 @@ */ - #include "common/system.h" #include "agos/agos.h" @@ -339,10 +338,10 @@ void AGOSEngine_Simon1::os1_pauseGame() { break; } - while (!_quit) { + while (!quit()) { delay(1); if (_keyPressed.keycode == keyYes) - _quit = true; + quitGame(); else if (_keyPressed.keycode == keyNo) break; } diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp index 8dc915f6e8..f0da324fbd 100644 --- a/engines/agos/script_ww.cpp +++ b/engines/agos/script_ww.cpp @@ -368,11 +368,11 @@ void AGOSEngine_Waxworks::oww_pauseGame() { uint32 pauseTime = getTime(); haltAnimation(); - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; - while (!_quit) { + while (!quit()) { if (_lastHitArea3 != 0) break; delay(1); diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp index c456c92e60..4d60bbdbed 100644 --- a/engines/agos/sound.cpp +++ b/engines/agos/sound.cpp @@ -56,10 +56,12 @@ protected: public: BaseSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false); BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigEndian = false); + virtual ~BaseSound(); + void close(); + void playSound(uint sound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0) { playSound(sound, sound, type, handle, flags, vol); } - virtual ~BaseSound(); virtual void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0) = 0; virtual Audio::AudioStream *makeAudioStream(uint sound) { return NULL; } }; @@ -184,6 +186,12 @@ BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigE _freeOffsets = false; } +void BaseSound::close() { + if (_freeOffsets) { + free(_offsets); + } +} + BaseSound::~BaseSound() { if (_freeOffsets) free(_offsets); @@ -555,6 +563,9 @@ void Sound::readSfxFile(const char *filename) { void Sound::loadSfxTable(File *gameFile, uint32 base) { stopAll(); + + if (_effects) + _effects->close(); if (_vm->getPlatform() == Common::kPlatformWindows) _effects = new WavSound(_mixer, gameFile, base); diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp index cb71ed7efa..488ebf4edf 100644 --- a/engines/agos/subroutine.cpp +++ b/engines/agos/subroutine.cpp @@ -555,7 +555,7 @@ int AGOSEngine::startSubroutine(Subroutine *sub) { _currentTable = sub; restart: - if (_quit) + if (quit()) return result; while ((byte *)sl != (byte *)sub) { diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp index c8f6d40f1f..9fd128d764 100644 --- a/engines/agos/verb.cpp +++ b/engines/agos/verb.cpp @@ -343,7 +343,7 @@ void AGOSEngine::handleVerbClicked(uint verb) { Subroutine *sub; int result; - if (_quit) + if (quit()) return; _objectItem = _hitAreaObjectItem; diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp index e1f986b92e..87db49e46b 100644 --- a/engines/agos/window.cpp +++ b/engines/agos/window.cpp @@ -298,11 +298,11 @@ void AGOSEngine::waitWindow(WindowBlock *window) { ha->id = 0x7FFF; ha->priority = 999; - while (!_quit) { + while (!quit()) { _lastHitArea = NULL; _lastHitArea3 = NULL; - for (;;) { + while (!quit()) { if (_lastHitArea3 != 0) break; delay(1); diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index a670328c12..f5cde579e6 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -53,7 +53,6 @@ Common::Array<AnimData> animDataTable; static const AnimDataEntry transparencyData[] = { {"ALPHA", 0xF}, - {"TITRE", 0xF}, {"TITRE2", 0xF}, {"ET", 0xC}, {"L311", 0x3}, @@ -586,6 +585,14 @@ int loadAni(const char *resourceName, int16 idx) { transparentColor = getAnimTransparentColor(resourceName); + // TODO: Merge this special case hack into getAnimTransparentColor somehow. + // HACK: Versions of TITRE.ANI with height 37 use color 0xF for transparency. + // Versions of TITRE.ANI with height 57 use color 0x0 for transparency. + // Fixes bug #2057619: FW: Glitches in title display of demo (regression). + if (scumm_stricmp(resourceName, "TITRE.ANI") == 0 && animHeader.frameHeight == 37) { + transparentColor = 0xF; + } + entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); @@ -761,7 +768,7 @@ int loadResource(const char *resourceName, int16 idx) { } else if (strstr(resourceName, ".AMI")) { warning("loadResource: Ignoring file '%s' (Load at %d)", resourceName, idx); } else if (strstr(resourceName, "ECHEC")) { // Echec (French) means failure - exitEngine = 1; + g_cine->quitGame(); } else { error("loadResource: Cannot determine type for '%s'", resourceName); } diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index 45bfae7925..cc7e843c2b 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -41,10 +41,18 @@ byte loadCtFW(const char *ctName) { uint16 header[32]; byte *ptr, *dataPtr; + int16 foundFileIdx = findFileInBundle(ctName); + if (foundFileIdx == -1) { + warning("loadCtFW: Unable to find collision data file '%s'", ctName); + // FIXME: Rework this function's return value policy and return an appropriate value here. + // The return value isn't yet used for anything so currently it doesn't really matter. + return 0; + } + if (currentCtName != ctName) strcpy(currentCtName, ctName); - ptr = dataPtr = readBundleFile(findFileInBundle(ctName)); + ptr = dataPtr = readBundleFile(foundFileIdx); loadRelatedPalette(ctName); diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 9eb751835e..2c0fdc7d88 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -23,7 +23,6 @@ * */ -#include "common/events.h" #include "common/file.h" #include "common/savefile.h" #include "common/config-manager.h" @@ -101,6 +100,7 @@ int CineEngine::go() { delete renderer; delete[] collisionPage; delete g_sound; + return 0; } diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp index b15f30c35c..91ef964a0b 100644 --- a/engines/cine/detection.cpp +++ b/engines/cine/detection.cpp @@ -533,8 +533,17 @@ public: } virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; + virtual SaveStateList listSaves(const char *target) const; }; +bool CineMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad); +} + bool CineMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Cine::CINEGameDescription *gd = (const Cine::CINEGameDescription *)desc; if (gd) { @@ -543,6 +552,50 @@ bool CineMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common return gd != 0; } +SaveStateList CineMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + SaveStateList saveList; + + Common::String pattern = target; + pattern += ".?"; + Common::StringList filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); + Common::StringList::const_iterator file = filenames.begin(); + + Common::String filename = target; + filename += ".dir"; + Common::InSaveFile *in = saveFileMan->openForLoading(filename.c_str()); + if (in) { + int8 ch; + char saveDesc[20]; + do { + // Obtain the last digit of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 1); + + uint pos = 0; + do { + ch = in->readByte(); + if (pos < (sizeof(saveDesc) - 1)) { + if (ch < 32 || in->eos()) { + saveDesc[pos++] = '\0'; + } + else if (ch >= 32) { + saveDesc[pos++] = ch; + } + } + } while (ch >= 32 && !in->eos()); + if (saveDesc[0] != 0) { + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + file++; + } + } while (!in->eos()); + } + + delete in; + + return saveList; +} + #if PLUGIN_ENABLED_DYNAMIC(CINE) REGISTER_PLUGIN_DYNAMIC(CINE, PLUGIN_TYPE_ENGINE, CineMetaEngine); #else diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index cb900e8850..e24b23f7f0 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -200,9 +200,15 @@ void FWRenderer::incrustSprite(const objectStruct &obj) { width = animDataTable[obj.frame]._realWidth; height = animDataTable[obj.frame]._height; - assert(mask); - - drawSpriteRaw(data, mask, width, height, _background, x, y); + // There was an assert(mask) here before but it made savegame loading + // in Future Wars sometimes fail the assertion (e.g. see bug #2055912). + // Not drawing sprites that have no mask seems to work, but not sure + // if this is really a correct way to fix this. + if (mask) { + drawSpriteRaw(data, mask, width, height, _background, x, y); + } else { // mask == NULL + warning("FWRenderer::incrustSprite: Skipping maskless sprite (frame=%d)", obj.frame); + } } /*! \brief Draw command box on screen @@ -368,7 +374,7 @@ int FWRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); + drawSpriteRaw(g_cine->_textHandler.textTable[idx][FONT_DATA], g_cine->_textHandler.textTable[idx][FONT_MASK], FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y); x += width + 1; } @@ -436,6 +442,9 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: + if (objectTable[it->objIdx].frame < 0) { + return; + } sprite = &animDataTable[objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; @@ -1037,7 +1046,7 @@ int OSRenderer::drawChar(char character, int x, int y) { x += 5; } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; - drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); + drawSpriteRaw2(g_cine->_textHandler.textTable[idx][FONT_DATA], 0, FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y); x += width + 1; } @@ -1664,6 +1673,16 @@ void gfxResetRawPage(byte *pageRaw) { } void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h) { + // Output is 4 bits per pixel. + // Pixels are in 16 pixel chunks (8 bytes of source per 16 pixels of output). + // The source data is interleaved so that + // 1st big-endian 16-bit value contains all bit position 0 values for 16 pixels, + // 2nd big-endian 16-bit value contains all bit position 1 values for 16 pixels, + // 3rd big-endian 16-bit value contains all bit position 2 values for 16 pixels, + // 4th big-endian 16-bit value contains all bit position 3 values for 16 pixels. + // 1st pixel's bits are in the 16th bits, + // 2nd pixel's bits are in the 15th bits, + // 3rd pixel's bits are in the 14th bits etc. for (int y = 0; y < h; ++y) { for (int x = 0; x < w / 8; ++x) { for (int bit = 0; bit < 16; ++bit) { diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index e2402a4c8d..04c6f5c769 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -25,7 +25,6 @@ #include "common/scummsys.h" -#include "common/events.h" #include "common/system.h" #include "cine/main_loop.h" @@ -61,9 +60,6 @@ static void processEvent(Common::Event &event) { break; case Common::EVENT_MOUSEMOVE: break; - case Common::EVENT_QUIT: - exitEngine = 1; - break; case Common::EVENT_KEYDOWN: switch (event.kbd.keycode) { case Common::KEYCODE_RETURN: @@ -258,13 +254,9 @@ void purgeSeqList() { void CineEngine::mainLoop(int bootScriptIdx) { bool playerAction; - uint16 quitFlag; byte di; uint16 mouseButton; - quitFlag = 0; - exitEngine = 0; - if (_preLoad == false) { resetBgIncrustList(); @@ -418,7 +410,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { if ("quit"[menuCommandLen] == (char)di) { ++menuCommandLen; if (menuCommandLen == 4) { - quitFlag = 1; + quitGame(); } } else { menuCommandLen = 0; @@ -427,7 +419,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { manageEvents(); - } while (!exitEngine && !quitFlag && _danKeysPressed != 7); + } while (!quit() && _danKeysPressed != 7); hideMouse(); g_sound->stopMusic(); diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index 657471be4e..7679d9d380 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -123,13 +123,13 @@ void CineEngine::readVolCnf() { unpackedSize = packedSize = f.size(); } uint8 *buf = new uint8[unpackedSize]; - f.read(buf, packedSize); - if (packedSize != unpackedSize) { - CineUnpacker cineUnpacker; - if (!cineUnpacker.unpack(buf, packedSize, buf, unpackedSize)) { - error("Error while unpacking 'vol.cnf' data"); - } + uint8 *packedBuf = new uint8[packedSize]; + f.read(packedBuf, packedSize); + CineUnpacker cineUnpacker; + if (!cineUnpacker.unpack(packedBuf, packedSize, buf, unpackedSize)) { + error("Error while unpacking 'vol.cnf' data"); } + delete[] packedBuf; uint8 *p = buf; int resourceFilesCount = READ_BE_UINT16(p); p += 2; int entrySize = READ_BE_UINT16(p); p += 2; @@ -211,26 +211,23 @@ int16 findFileInBundle(const char *fileName) { } void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) { + assert(maxSize >= partBuffer[idx].packedSize); setMouseCursor(MOUSE_CURSOR_DISK); g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET); - g_cine->_partFileHandle.read(dataPtr, MIN(partBuffer[idx].packedSize, maxSize)); + g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize); } byte *readBundleFile(int16 foundFileIdx, uint32 *size) { assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size()); bool error = false; byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1); - readFromPart(foundFileIdx, dataPtr, partBuffer[foundFileIdx].unpackedSize); - if (partBuffer[foundFileIdx].unpackedSize > partBuffer[foundFileIdx].packedSize) { - CineUnpacker cineUnpacker; - error = !cineUnpacker.unpack(dataPtr, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); - } else if (partBuffer[foundFileIdx].unpackedSize < partBuffer[foundFileIdx].packedSize) { - // Unpacked size of a file should never be less than its packed size - error = true; - } else { // partBuffer[foundFileIdx].unpackedSize == partBuffer[foundFileIdx].packedSize - debugC(5, kCineDebugPart, "Loaded non-compressed file '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); - } + byte *packedData = (byte *)calloc(partBuffer[foundFileIdx].packedSize, 1); + assert(dataPtr && packedData); + readFromPart(foundFileIdx, packedData, partBuffer[foundFileIdx].packedSize); + CineUnpacker cineUnpacker; + error = !cineUnpacker.unpack(packedData, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); + free(packedData); if (error) { warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp index 5d789f9b3b..797a354c4f 100644 --- a/engines/cine/prc.cpp +++ b/engines/cine/prc.cpp @@ -25,6 +25,7 @@ #include "common/endian.h" +#include "common/events.h" #include "cine/cine.h" #include "cine/various.h" @@ -54,7 +55,9 @@ bool loadPrc(const char *pPrcName) { // This is copy protection. Used to hang the machine if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) { - exitEngine = 1; + Common::Event event; + event.type = Common::EVENT_RTL; + g_system->getEventManager()->pushEvent(event); return false; } diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 97f45488f2..6c13647ff3 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1501,7 +1501,18 @@ int FWScript::o1_compareGlobalVar() { debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value); - _compare = compareVars(_globalVars[varIdx], value); + // WORKAROUND for bug #2054882. Without this, the monks will always + // kill you as an impostor, even if you enter the monastery in disguise. + // + // TODO: Check whether this might be worked around in some other way + // like setting global variable 255 to 143 in Future Wars (This is + // supposedly what Future Wars checks for from time to time during + // gameplay to verify that copy protection was successfully passed). + if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) { + _compare = kCmpEQ; + } else { + _compare = compareVars(_globalVars[varIdx], value); + } } return 0; diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 3618350476..164c5a9ca5 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -79,13 +79,13 @@ const int PCSoundDriver::_noteTable[] = { const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable); struct AdlibRegisterSoundInstrument { - uint16 vibrato; - uint16 attackDecay; - uint16 sustainRelease; - uint16 feedbackStrength; - uint16 keyScaling; - uint16 outputLevel; - uint16 freqMod; + uint8 vibrato; + uint8 attackDecay; + uint8 sustainRelease; + uint8 feedbackStrength; + uint8 keyScaling; + uint8 outputLevel; + uint8 freqMod; }; struct AdlibSoundInstrument { diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index 33c16159ec..ffc36b4b1a 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -39,6 +39,13 @@ const char **commandPrepositionTable; void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); +/*! \brief Loads font data from the given file. + * The number of characters used in the font varies between game versions: + * 78 (Most PC, Amiga and Atari ST versions of Future Wars, but also Operation Stealth's Amiga demo), + * 85 (All observed versions of German Future Wars (Amiga and PC), possibly Spanish Future Wars too), + * 90 (Most PC, Amiga and Atari ST versions of Operation Stealth), + * 93 (All observed versions of German Operation Stealth (Amiga and PC)). + */ void loadTextData(const char *filename) { Common::File fileHandle; assert(filename); @@ -46,30 +53,29 @@ void loadTextData(const char *filename) { if (!fileHandle.open(filename)) error("loadTextData(): Cannot open file %s", filename); - uint entrySize = fileHandle.readUint16BE(); - uint numEntry = fileHandle.readUint16BE(); + static const uint headerSize = 2 + 2; // The entry size (16-bit) and entry count (16-bit). + const uint entrySize = fileHandle.readUint16BE(); // Observed values: 8. + const uint entryCount = fileHandle.readUint16BE(); // Observed values: 624, 680, 720, 744. + const uint fontDataSize = entryCount * entrySize; // Observed values: 4992, 5440, 5760, 5952. + const uint numChars = entryCount / entrySize; // Observed values: 78, 85, 90, 93. + const uint bytesPerChar = fontDataSize / numChars; // Observed values: 64. + static const uint bytesPerRow = FONT_WIDTH / 2; // The input font data is 4-bit so it takes only half the space + + if (headerSize + fontDataSize != (uint)fileHandle.size()) { + warning("loadTextData: file '%s' (entrySize = %d, entryCount = %d) is of incorrect size %d", filename, entrySize, entryCount, fileHandle.size()); + } - uint sourceSize = numEntry * entrySize; Common::Array<byte> source; - source.resize(sourceSize); - fileHandle.read(source.begin(), sourceSize); + source.resize(fontDataSize); + fileHandle.read(source.begin(), fontDataSize); - const int fontHeight = 8; - const int fontWidth = (g_cine->getGameType() == Cine::GType_FW) ? 16 : 8; - uint numCharacters; - uint bytesPerCharacter; if (g_cine->getGameType() == Cine::GType_FW) { - numCharacters = (g_cine->getFeatures() & GF_ALT_FONT) ? 85 : 78; - bytesPerCharacter = sourceSize / numCharacters; // TODO: Check if this could be replaced with fontWidth * fontHeight loadRelatedPalette(filename); - } else { - numCharacters = 90; - bytesPerCharacter = fontWidth * fontHeight; } - for (uint i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], &source[i * bytesPerCharacter], fontWidth, fontHeight); - generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], fontWidth * fontHeight, 0); + for (uint i = 0; i < numChars; i++) { + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][FONT_DATA], &source[i * bytesPerChar], bytesPerRow, FONT_HEIGHT); + generateMask(g_cine->_textHandler.textTable[i][FONT_DATA], g_cine->_textHandler.textTable[i][FONT_MASK], FONT_WIDTH * FONT_HEIGHT, 0); } fileHandle.close(); diff --git a/engines/cine/texte.h b/engines/cine/texte.h index bc4beac492..0b1fc88e86 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -36,13 +36,20 @@ typedef char CommandeType[20]; // Number of characters in a font #define NUM_FONT_CHARS 256 +#define FONT_WIDTH 16 +#define FONT_HEIGHT 8 + +// Used for choosing between font's data and font's mask +#define FONT_DATA 0 +#define FONT_MASK 1 + struct CharacterEntry { byte characterIdx; byte characterWidth; }; struct TextHandler { - byte textTable[NUM_FONT_CHARS][2][16 * 8]; + byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH * FONT_HEIGHT]; CharacterEntry fontParamTable[NUM_FONT_CHARS]; }; diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp index 5d85ff6cab..7915fd1cf8 100644 --- a/engines/cine/unpack.cpp +++ b/engines/cine/unpack.cpp @@ -100,6 +100,14 @@ bool CineUnpacker::unpack(const byte *src, uint srcLen, byte *dst, uint dstLen) _dstBegin = dst; _dstEnd = dst + dstLen; + // Handle already unpacked data here + if (srcLen == dstLen) { + // Source length is same as destination length so the source + // data is already unpacked. Let's just copy it then. + memcpy(dst, src, srcLen); + return true; + } + // Initialize other variables _src = _srcBegin + srcLen - 4; uint32 unpackedLength = readSource(); // Unpacked length in bytes diff --git a/engines/cine/unpack.h b/engines/cine/unpack.h index e16cb594a9..2355df5ee1 100644 --- a/engines/cine/unpack.h +++ b/engines/cine/unpack.h @@ -35,14 +35,14 @@ namespace Cine { * A LZ77 style decompressor for Delphine's data files * used in at least Future Wars and Operation Stealth. * @note Works backwards in the source and destination buffers. - * @note Can work with source and destination in the same buffer if there's space. + * @warning Having the source and destination in the same buffer when unpacking can cause errors! */ class CineUnpacker { public: /** * Unpacks packed data from the source buffer to the destination buffer. - * @warning Do NOT call this on data that is not packed. - * @note Source and destination buffer pointers can be the same as long as there's space for the unpacked data. + * @note You may call this on already unpacked data but then source length must be equal to destination length. + * @warning The source and destination should not point to the same buffer. If they do, errors may occur! * @param src Pointer to the source buffer. * @param srcLen Length of the source buffer. * @param dst Pointer to the destination buffer. diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index e96e03b03c..92fd35d865 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -25,7 +25,6 @@ #include "common/endian.h" -#include "common/events.h" #include "common/savefile.h" #include "cine/cine.h" @@ -125,7 +124,6 @@ static const int16 canUseOnItemTable[] = { 1, 0, 0, 1, 1, 0, 0 }; CommandeType objectListCommand[20]; int16 objListTab[20]; -uint16 exitEngine; Common::Array<uint16> zoneData; Common::Array<uint16> zoneQuery; //!< Only exists in Operation Stealth @@ -499,7 +497,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle uint animEntrySize = animEntrySizeChoices[i]; // Jump over the animDataTable entries and the screen parameters - uint32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; + int32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; // Check that there's data left after the point we're going to jump to if (newPos >= fHandle.size()) { continue; @@ -1094,7 +1092,7 @@ bool CineEngine::makeLoad(char *saveName) { // that's not implemented here because it was never used in a stable // release of ScummVM but only during development (From revision 31453, // which introduced the problem, until revision 32073, which fixed it). - // Therefore be bail out if we detect this particular savegame format. + // Therefore we bail out if we detect this particular savegame format. warning("Detected a known broken savegame format, not loading savegame"); load = false; // Don't load the savegame } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { @@ -1223,7 +1221,7 @@ void CineEngine::makeSystemMenu(void) { { getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY); if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) { - exitEngine = 1; + quitGame(); } break; } diff --git a/engines/cine/various.h b/engines/cine/various.h index 0ee77c1b47..b841908c65 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -120,8 +120,6 @@ void mainLoopSub6(void); void checkForPendingDataLoad(void); -extern uint16 exitEngine; - void hideMouse(void); void removeExtention(char *dest, const char *source); diff --git a/engines/cruise/object.cpp b/engines/cruise/object.cpp index 66a3a53018..bb8d85acd0 100644 --- a/engines/cruise/object.cpp +++ b/engines/cruise/object.cpp @@ -58,7 +58,7 @@ objDataStruct *getObjectDataFromOverlay(int ovlIdx, int objIdx) { } int16 getMultipleObjectParam(int16 overlayIdx, int16 objectIdx, objectParamsQuery *returnParam) { - objectParams *ptr2; + objectParams *ptr2 = 0; objDataStruct *ptr; ovlDataStruct *ovlData; // int16 type; @@ -246,7 +246,7 @@ int16 getSingleObjectParam(int16 overlayIdx, int16 param2, int16 param3, int16 * //char* ptr3 = NULL; objDataStruct *ptr; ovlDataStruct *ovlData; - objectParams *ptr2; + objectParams *ptr2 = 0; ptr = getObjectDataFromOverlay(overlayIdx, param2); diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h index a325de3f36..5f65446cc5 100644 --- a/engines/cruise/vars.h +++ b/engines/cruise/vars.h @@ -86,7 +86,7 @@ struct filesData2Struct { int16 field_2; }; -struct fileName { +struct dataFileName { char name[13]; }; @@ -103,7 +103,7 @@ struct setHeaderEntry { struct volumeDataStruct { char ident[10]; - fileName *ptr; + dataFileName *ptr; int16 diskNumber; int32 size; }; diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp index b2ff2631c0..47e2f02184 100644 --- a/engines/cruise/volume.cpp +++ b/engines/cruise/volume.cpp @@ -395,12 +395,12 @@ int16 readVolCnf(void) { } for (i = 0; i < numOfDisks; i++) { - fileName *ptr; + dataFileName *ptr; fileHandle.read(&volumeData[i].size, 4); flipLong(&volumeData[i].size); - ptr = (fileName *) mallocAndZero(volumeData[i].size); + ptr = (dataFileName *) mallocAndZero(volumeData[i].size); volumeData[i].ptr = ptr; diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp new file mode 100644 index 0000000000..8d8888246b --- /dev/null +++ b/engines/dialogs.cpp @@ -0,0 +1,264 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "base/version.h" + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/system.h" +#include "common/events.h" + +#include "graphics/scaler.h" + +#include "gui/about.h" +#include "gui/newgui.h" +#include "gui/ListWidget.h" +#include "gui/theme.h" + +#include "engines/dialogs.h" +#include "engines/engine.h" +#include "engines/metaengine.h" + +#ifdef SMALL_SCREEN_DEVICE +#include "gui/KeysDialog.h" +#endif + +using GUI::CommandSender; +using GUI::StaticTextWidget; +using GUI::kButtonWidth; +using GUI::kButtonHeight; +using GUI::kBigButtonWidth; +using GUI::kBigButtonHeight; +using GUI::kCloseCmd; +using GUI::kTextAlignCenter; +using GUI::kTextAlignLeft; +using GUI::WIDGET_ENABLED; + +typedef GUI::OptionsDialog GUI_OptionsDialog; +typedef GUI::Dialog GUI_Dialog; + +GlobalDialog::GlobalDialog(String name) : GUI::Dialog(name) {} + +enum { + kSaveCmd = 'SAVE', + kLoadCmd = 'LOAD', + kPlayCmd = 'PLAY', + kOptionsCmd = 'OPTN', + kHelpCmd = 'HELP', + kAboutCmd = 'ABOU', + kQuitCmd = 'QUIT', + kRTLCmd = 'RTL ', + kChooseCmd = 'CHOS' +}; + +MainMenuDialog::MainMenuDialog(Engine *engine) + : GlobalDialog("globalmain"), _engine(engine) { + +#ifndef DISABLE_FANCY_THEMES + _logo = 0; + if (g_gui.xmlEval()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) { + _logo = new GUI::GraphicsWidget(this, "global_logo"); + _logo->useThemeTransparency(true); + _logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall)); + } else { + new StaticTextWidget(this, "global_title", "ScummVM"); + } +#else + new StaticTextWidget(this, "global_title", "ScummVM"); +#endif + + new StaticTextWidget(this, "global_version", gScummVMVersionDate); + + new GUI::ButtonWidget(this, "globalmain_resume", "Resume", kPlayCmd, 'P'); + +// new GUI::ButtonWidget(this, "globalmain_load", "Load", kLoadCmd, 'L'); +// new GUI::ButtonWidget(this, "globalmain_save", "Save", kSaveCmd, 'S'); + + new GUI::ButtonWidget(this, "globalmain_options", "Options", kOptionsCmd, 'O'); + + new GUI::ButtonWidget(this, "globalmain_about", "About", kAboutCmd, 'A'); + + _rtlButton = new GUI::ButtonWidget(this, "globalmain_rtl", "Return to Launcher", kRTLCmd, 'R'); + // '0' corresponds to the kSupportsRTL MetaEngineFeature + _rtlButton->setEnabled(_engine->hasFeature(0)); + + + new GUI::ButtonWidget(this, "globalmain_quit", "Quit", kQuitCmd, 'Q'); + + _aboutDialog = new GUI::AboutDialog(); + _optionsDialog = new ConfigDialog(); +} + +MainMenuDialog::~MainMenuDialog() { + delete _aboutDialog; + delete _optionsDialog; +} + +void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + switch (cmd) { + case kPlayCmd: + close(); + break; + case kOptionsCmd: + _optionsDialog->runModal(); + break; + case kAboutCmd: + _aboutDialog->runModal(); + break; + case kRTLCmd: { + Common::Event eventRTL; + eventRTL.type = Common::EVENT_RTL; + g_system->getEventManager()->pushEvent(eventRTL); + close(); + } + break; + case kQuitCmd: { + Common::Event eventQ; + eventQ.type = Common::EVENT_QUIT; + g_system->getEventManager()->pushEvent(eventQ); + close(); + } + break; + default: + GlobalDialog::handleCommand(sender, cmd, data); + } +} + +void MainMenuDialog::reflowLayout() { +#ifndef DISABLE_FANCY_THEMES + if (g_gui.xmlEval()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) { + if (!_logo) + _logo = new GUI::GraphicsWidget(this, "global_logo"); + _logo->useThemeTransparency(true); + _logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall)); + + GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title"); + if (title) { + removeWidget(title); + title->setNext(0); + delete title; + } + } else { + GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title"); + if (!title) + new StaticTextWidget(this, "global_title", "ScummVM"); + + if (_logo) { + removeWidget(_logo); + _logo->setNext(0); + delete _logo; + _logo = 0; + } + } +#endif + + Dialog::reflowLayout(); +} + +enum { + kOKCmd = 'ok ' +}; + +enum { + kKeysCmd = 'KEYS' +}; + +// FIXME: We use the empty string as domain name here. This tells the +// ConfigManager to use the 'default' domain for all its actions. We do that +// to get as close as possible to editing the 'active' settings. +// +// However, that requires bad & evil hacks in the ConfigManager code, +// and even then still doesn't work quite correctly. +// For example, if the transient domain contains 'false' for the 'fullscreen' +// flag, but the user used a hotkey to switch to windowed mode, then the dialog +// will display the wrong value anyway. +// +// Proposed solution consisting of multiple steps: +// 1) Add special code to the open() code that reads out everything stored +// in the transient domain that is controlled by this dialog, and updates +// the dialog accordingly. +// 2) Even more code is added to query the backend for current settings, like +// the fullscreen mode flag etc., and also updates the dialog accordingly. +// 3) The domain being edited is set to the active game domain. +// 4) If the dialog is closed with the "OK" button, then we remove everything +// stored in the transient domain (or at least everything corresponding to +// switches in this dialog. +// If OTOH the dialog is closed with "Cancel" we do no such thing. +// +// These changes will achieve two things at once: Allow us to get rid of using +// "" as value for the domain, and in fact provide a somewhat better user +// experience at the same time. +ConfigDialog::ConfigDialog() + : GUI::OptionsDialog("", "scummconfig") { + + // + // Sound controllers + // + + addVolumeControls(this, "scummconfig_"); + + // + // Some misc options + // + + // SCUMM has a talkspeed range of 0-9 + addSubtitleControls(this, "scummconfig_", 9); + + // + // Add the buttons + // + + new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O'); + new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C'); + +#ifdef SMALL_SCREEN_DEVICE + new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K'); + + // + // Create the sub dialog(s) + // + + _keysDialog = new GUI::KeysDialog(); +#endif +} + +ConfigDialog::~ConfigDialog() { +#ifdef SMALL_SCREEN_DEVICE + delete _keysDialog; +#endif +} + +void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + switch (cmd) { + case kKeysCmd: + +#ifdef SMALL_SCREEN_DEVICE + _keysDialog->runModal(); +#endif + break; + default: + GUI_OptionsDialog::handleCommand (sender, cmd, data); + } +} + diff --git a/engines/dialogs.h b/engines/dialogs.h new file mode 100644 index 0000000000..66ea13b8f1 --- /dev/null +++ b/engines/dialogs.h @@ -0,0 +1,77 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#ifndef GLOBAL_DIALOGS_H +#define GLOBAL_DIALOGS_H + +#include "common/str.h" +#include "gui/dialog.h" +#include "gui/options.h" +#include "gui/widget.h" + +#include "engines/engine.h" + + +class GlobalDialog : public GUI::Dialog { +public: + GlobalDialog(Common::String name); + +protected: + typedef Common::String String; +}; + + +class MainMenuDialog : public GlobalDialog { +public: + MainMenuDialog(Engine *engine); + ~MainMenuDialog(); + + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + + virtual void reflowLayout(); + +protected: + Engine *_engine; + + GUI::GraphicsWidget *_logo; + GUI::ButtonWidget *_rtlButton; + GUI::Dialog *_aboutDialog; + GUI::Dialog *_optionsDialog; + +}; + +class ConfigDialog : public GUI::OptionsDialog { +protected: +#ifdef SMALL_SCREEN_DEVICE + GUI::Dialog *_keysDialog; +#endif + +public: + ConfigDialog(); + ~ConfigDialog(); + + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); +}; + +#endif diff --git a/engines/drascula/actors.cpp b/engines/drascula/actors.cpp index 10ce415c2c..ff46d8201a 100644 --- a/engines/drascula/actors.cpp +++ b/engines/drascula/actors.cpp @@ -28,45 +28,45 @@ namespace Drascula { void DrasculaEngine::placeIgor() { - int pos_igor[6] = { 1, 0, igorX, igorY, 54, 61 }; + int igY = 0; if (currentChapter == 4) { - pos_igor[1] = 138; + igY = 138; } else { if (trackIgor == 3) - pos_igor[1] = 138; + igY = 138; else if (trackIgor == 1) - pos_igor[1] = 76; + igY = 76; } - copyRectClip(pos_igor, frontSurface, screenSurface); + copyRect(1, igY, igorX, igorY, 54, 61, frontSurface, screenSurface); } void DrasculaEngine::placeDrascula() { - int pos_dr[6] = { 0, 122, drasculaX, drasculaY, 45, 77 }; + int drX = 0; if (trackDrascula == 1) - pos_dr[0] = 47; + drX = 47; else if (trackDrascula == 0) - pos_dr[0] = 1; + drX = 1; else if (trackDrascula == 3 && currentChapter == 1) - pos_dr[0] = 93; + drX = 93; if (currentChapter == 6) - copyRectClip(pos_dr, drawSurface2, screenSurface); + copyRect(drX, 122, drasculaX, drasculaY, 45, 77, drawSurface2, screenSurface); else - copyRectClip(pos_dr, backSurface, screenSurface); + copyRect(drX, 122, drasculaX, drasculaY, 45, 77, backSurface, screenSurface); } void DrasculaEngine::placeBJ() { - int pos_bj[6] = { 0, 99, bjX, bjY, 26, 76 }; + int bX = 0; if (trackBJ == 3) - pos_bj[0] = 10; + bX = 10; else if (trackBJ == 0) - pos_bj[0] = 37; + bX = 37; - copyRectClip(pos_bj, drawSurface3, screenSurface); + copyRect(bX, 99, bjX, bjY, 26, 76, drawSurface3, screenSurface); } void DrasculaEngine::hiccup(int counter) { @@ -189,7 +189,7 @@ void DrasculaEngine::moveCharacters() { } } - if (currentChapter == 1 || currentChapter == 4 || currentChapter == 5 || currentChapter == 6) { + if (currentChapter != 2 && currentChapter != 3) { if (hare_se_ve == 0) { increaseFrameNum(); return; @@ -212,25 +212,29 @@ void DrasculaEngine::moveCharacters() { if (trackProtagonist == 0) { curPos[1] = 0; if (currentChapter == 2) - copyRectClip(curPos, extraSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + extraSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], extraSurface, screenSurface); } else if (trackProtagonist == 1) { if (currentChapter == 2) - copyRectClip(curPos, extraSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + extraSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], extraSurface, screenSurface); } else if (trackProtagonist == 2) { if (currentChapter == 2) - copyRectClip(curPos, backSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + backSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], backSurface, screenSurface); } else { if (currentChapter == 2) - copyRectClip(curPos, frontSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + frontSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], frontSurface, screenSurface); @@ -250,25 +254,29 @@ void DrasculaEngine::moveCharacters() { if (trackProtagonist == 0) { curPos[1] = 0; if (currentChapter == 2) - copyRectClip(curPos, extraSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + extraSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], extraSurface, screenSurface); } else if (trackProtagonist == 1) { if (currentChapter == 2) - copyRectClip(curPos, extraSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + extraSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], extraSurface, screenSurface); } else if (trackProtagonist == 2) { if (currentChapter == 2) - copyRectClip(curPos, backSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + backSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], backSurface, screenSurface); } else { if (currentChapter == 2) - copyRectClip(curPos, frontSurface, screenSurface); + copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], + frontSurface, screenSurface); else reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5], factor_red[curY + curHeight], frontSurface, screenSurface); @@ -288,11 +296,11 @@ void DrasculaEngine::quadrant_1() { distanceY = (curY + curHeight) - roomY; if (distanceX < distanceY) { - curDirection = 0; + curDirection = kDirectionUp; trackProtagonist = 2; stepX = (int)(distanceX / (distanceY / STEP_Y)); } else { - curDirection = 7; + curDirection = kDirectionUp; trackProtagonist = 0; stepY = (int)(distanceY / (distanceX / STEP_X)); } @@ -309,11 +317,11 @@ void DrasculaEngine::quadrant_2() { distanceY = (curY + curHeight) - roomY; if (distanceX < distanceY) { - curDirection = 1; + curDirection = kDirectionRight; trackProtagonist = 2; stepX = (int)(distanceX / (distanceY / STEP_Y)); } else { - curDirection = 2; + curDirection = kDirectionRight; trackProtagonist = 1; stepY = (int)(distanceY / (distanceX / STEP_X)); } @@ -330,11 +338,11 @@ void DrasculaEngine::quadrant_3() { distanceY = roomY - (curY + curHeight); if (distanceX < distanceY) { - curDirection = 5; + curDirection = kDirectionLeft; trackProtagonist = 3; stepX = (int)(distanceX / (distanceY / STEP_Y)); } else { - curDirection = 6; + curDirection = kDirectionLeft; trackProtagonist = 0; stepY = (int)(distanceY / (distanceX / STEP_X)); } @@ -351,11 +359,11 @@ void DrasculaEngine::quadrant_4() { distanceY = roomY - (curY + curHeight); if (distanceX < distanceY) { - curDirection = 4; + curDirection = kDirectionDown; trackProtagonist = 3; stepX = (int)(distanceX / (distanceY / STEP_Y)); } else { - curDirection = 3; + curDirection = kDirectionDown; trackProtagonist = 1; stepY = (int)(distanceY / (distanceX / STEP_X)); } @@ -370,16 +378,16 @@ void DrasculaEngine::increaseFrameNum() { if (num_frame == 6) num_frame = 0; - if (curDirection == 0 || curDirection == 7) { + if (curDirection == kDirectionUp) { curX -= stepX; curY -= stepY; - } else if (curDirection == 1 || curDirection == 2) { + } else if (curDirection == kDirectionRight) { curX += stepX; curY -= stepY; - } else if (curDirection == 3 || curDirection == 4) { + } else if (curDirection == kDirectionDown) { curX += stepX; curY += stepY; - } else if (curDirection == 5 || curDirection == 6) { + } else if (curDirection == kDirectionLeft) { curX -= stepX; curY += stepY; } @@ -394,13 +402,13 @@ void DrasculaEngine::increaseFrameNum() { } void DrasculaEngine::walkDown() { - curDirection = 4; + curDirection = kDirectionDown; trackProtagonist = 3; stepX = 0; } void DrasculaEngine::walkUp() { - curDirection = 0; + curDirection = kDirectionUp; trackProtagonist = 2; stepX = 0; } @@ -432,7 +440,8 @@ void DrasculaEngine::moveVonBraun() { actorFrames[kFrameVonBraun] = 1; } - copyRectClip(pos_vb, frontSurface, screenSurface); + copyRect(pos_vb[0], pos_vb[1], pos_vb[2], pos_vb[3], pos_vb[4], pos_vb[5], + frontSurface, screenSurface); } void DrasculaEngine::placeVonBraun(int pointX) { diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 06868494b5..ad7fe64d0e 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -55,7 +55,7 @@ void DrasculaEngine::updateAnim2(int y, int px, int py, int width, int height, i // This is the game's introduction sequence void DrasculaEngine::animation_1_1() { int l, l2, p; - int pixelPos[6]; + //int pixelPos[6]; while (term_int == 0) { playMusic(29); @@ -87,7 +87,7 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; color_abc(kColorRed); - centerText(_textmisc[_lang][1], 160, 100); + centerText(_textmisc[1], 160, 100); updateScreen(); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; @@ -134,7 +134,7 @@ void DrasculaEngine::animation_1_1() { for (l2 = 0; l2 < 3; l2++) for (l = 0; l < 7; l++) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface); updateScreen(); if (getScan() == Common::KEYCODE_ESCAPE) { @@ -147,19 +147,13 @@ void DrasculaEngine::animation_1_1() { break; l2 = 0; p = 0; - pixelPos[3] = 45; - pixelPos[4] = 63; - pixelPos[5] = 31; for (l = 0; l < 180; l++) { copyBackground(0, 0, 320 - l, 0, l, 200, drawSurface3, screenSurface); copyBackground(l, 0, 0, 0, 320 - l, 200, bgSurface, screenSurface); - pixelPos[0] = interf_x[l2]; - pixelPos[1] = interf_y[l2]; - pixelPos[2] = 156 - l; - - copyRectClip(pixelPos, drawSurface2, screenSurface); + copyRect(interf_x[l2], interf_y[l2], 156 - l, 45, 63, 31, + drawSurface2, screenSurface); updateScreen(); p++; if (p == 6) { @@ -177,7 +171,7 @@ void DrasculaEngine::animation_1_1() { break; copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface); - talk_dr_grande(1); + talk_drascula_big(1); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; @@ -193,14 +187,14 @@ void DrasculaEngine::animation_1_1() { igorX = 66; igorY = 97; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); talk_igor(8, kIgorDch); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -219,12 +213,12 @@ void DrasculaEngine::animation_1_1() { loadPic("plan1.alg", screenSurface, HALF_PAL); updateScreen(); pause(10); - talk_solo(_textd[_lang][4],"d4.als"); + talk_solo(_textd[4],"d4.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; loadPic("plan1.alg", screenSurface, HALF_PAL); updateScreen(); - talk_solo(_textd[_lang][5], "d5.als"); + talk_solo(_textd[5], "d5.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; if (animate("lib2.bin", 16)) @@ -233,7 +227,7 @@ void DrasculaEngine::animation_1_1() { loadPic("plan2.alg", screenSurface, HALF_PAL); updateScreen(); pause(20); - talk_solo(_textd[_lang][6], "d6.als"); + talk_solo(_textd[6], "d6.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; if (animate("lib2.bin", 16)) @@ -244,12 +238,12 @@ void DrasculaEngine::animation_1_1() { pause(20); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - talk_solo(_textd[_lang][7], "d7.als"); + talk_solo(_textd[7], "d7.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; loadPic("plan3.alg", screenSurface, HALF_PAL); updateScreen(); - talk_solo(_textd[_lang][8], "d8.als"); + talk_solo(_textd[8], "d8.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; clearRoom(); @@ -297,13 +291,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -311,13 +305,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 1; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -329,13 +323,13 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; trackDrascula = 3; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); pause(1); trackDrascula = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); updateScreen(); @@ -402,9 +396,6 @@ void DrasculaEngine::animation_2_1() { if (animate("ag.bin", 14)) break; - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an11y13.alg", extraSurface); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; @@ -413,9 +404,6 @@ void DrasculaEngine::animation_2_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - if (_lang == kSpanish) - textSurface = extraSurface; - loadPic(97, extraSurface); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; @@ -436,7 +424,7 @@ void DrasculaEngine::animation_2_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - talk_solo(_textbj[_lang][1], "BJ1.als"); + talk_solo(_textbj[1], "BJ1.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; clearRoom(); @@ -449,7 +437,7 @@ void DrasculaEngine::animation_2_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; color_solo = kColorYellow; - talk_solo(_text[_lang][214], "214.als"); + talk_solo(_text[214], "214.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; clearRoom(); @@ -491,23 +479,8 @@ void DrasculaEngine::animation_2_1() { curX = 100; curY = 95; - talk_bj(2); - talk(215); - talk_bj(3); - talk(216); - talk_bj(4); - talk_bj(5); - talk_bj(6); - talk(217); - talk_bj(7); - talk(218); - talk_bj(8); - talk(219); - talk_bj(9); - talk(220); - talk(221); - talk_bj(10); - talk(222); + playTalkSequence(2); // sequence 2, chapter 1 + if (animate("gaf.bin", 15)) break; if (animate("bjb.bin", 14)) @@ -523,7 +496,7 @@ void DrasculaEngine::animation_2_1() { pause(120); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; - talk_solo(_text[_lang][223], "223.als"); + talk_solo(_text[223], "223.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; color_solo = kColorWhite; @@ -532,7 +505,7 @@ void DrasculaEngine::animation_2_1() { break; updateScreen(); pause(110); - talk_solo(_textbj[_lang][11], "BJ11.als"); + talk_solo(_textbj[11], "BJ11.als"); if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE)) break; updateRoom(); @@ -596,45 +569,17 @@ void DrasculaEngine::animation_2_1() { } } +// John Hacker talks with the bartender to book a room void DrasculaEngine::animation_3_1() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an11y13.alg", extraSurface); - talk(192); - talk_bartender(1); - talk(193); - talk_bartender(2); - talk(194); - talk_bartender(3); - talk(195); - talk_bartender(4); - talk(196); - talk_bartender(5); - talk_bartender(6); - talk(197); - talk_bartender(7); - talk(198); - talk_bartender(8); - talk(199); - talk_bartender(9); - talk(200); - talk(201); - talk(202); - - flags[0] = 1; - - if (_lang == kSpanish) - textSurface = extraSurface; + playTalkSequence(3); // sequence 3, chapter 1 loadPic(97, extraSurface); } +// John Hacker talks with the pianist void DrasculaEngine::animation_4_1() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an12.alg", extraSurface); talk(205); @@ -666,28 +611,20 @@ void DrasculaEngine::animation_4_1() { talk_pianist(4); talk(209); - if (_lang == kSpanish) - textSurface = extraSurface; - flags[11] = 0; loadPic(97, extraSurface); } -void DrasculaEngine::animation_1_2() { - gotoObject(178, 121); - gotoObject(169, 135); -} - void DrasculaEngine::animation_2_2() { trackProtagonist = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); moveCharacters(); updateRefresh(); updateScreen(); loadPic("an2_1.alg", frontSurface); loadPic("an2_2.alg", extraSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(1, 1, 201, 87, 50, 52, frontSurface, screenSurface); updateScreen(); @@ -701,7 +638,7 @@ void DrasculaEngine::animation_2_2() { updateAnim(55, 201, 87, 50, 52, 6, extraSurface); updateAnim(109, 201, 87, 50, 52, 2, extraSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); finishSound(); @@ -713,18 +650,12 @@ void DrasculaEngine::animation_2_2() { finishSound(); } -void DrasculaEngine::animation_3_2() { - gotoObject(163, 106); - gotoObject(287, 101); - trackProtagonist = 0; -} - void DrasculaEngine::animation_4_2() { stopMusic(); flags[9] = 1; pause(12); - talk(56); + talk(60); pause(8); clearRoom(); @@ -734,10 +665,7 @@ void DrasculaEngine::animation_4_2() { loadPic("ciego4.alg", backSurface); loadPic("ciego5.alg", frontSurface); - if (_lang == kSpanish) - textSurface = frontSurface; - - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -761,13 +689,13 @@ void DrasculaEngine::animation_4_2() { talk_blind(7); talk_hacker(63); talk_blind(8); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); _system->delayMillis(1000); talk_hacker(64); talk_blind(9); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(14); @@ -780,54 +708,25 @@ void DrasculaEngine::animation_4_2() { loadPic(96, frontSurface); loadPic(97, extraSurface); loadPic(99, backSurface); - withoutVerb(); - - if (_lang == kSpanish) - textSurface = extraSurface; + selectVerb(0); flags[9] = 0; flags[4] = 1; } -void DrasculaEngine::animation_8_2() { - talk_pianist(6); - talk(358); - talk_pianist(7); - talk_pianist(8); -} - -void DrasculaEngine::animation_9_2() { - talk_pianist(9); - talk_pianist(10); - talk_pianist(11); -} - -void DrasculaEngine::animation_10_2() { - talk_pianist(12); - talk(361); - pause(40); - talk_pianist(13); - talk(362); - talk_pianist(14); - talk(363); - talk_pianist(15); - talk(364); - talk_pianist(16); -} - void DrasculaEngine::animation_14_2() { - int cabinPos[6] = { 150, 6, 69, -160, 158, 161 }; + int cY = -160; int l = 0; loadPic("an14_2.alg", backSurface); for (int n = -160; n <= 0; n = n + 5 + l) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); moveVonBraun(); - cabinPos[3] = n; - copyRectClip(cabinPos, backSurface, screenSurface); + cY = n; + copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface); updateRefresh(); updateScreen(); l++; @@ -845,143 +744,64 @@ void DrasculaEngine::animation_14_2() { loadPic(99, backSurface); } -void DrasculaEngine::animation_15_2() { - talk_drunk(8); - pause(7); - talk_drunk(9); - talk_drunk(10); - talk_drunk(11); -} - +// The drunk tells us about Von Braun void DrasculaEngine::animation_16_2() { + char curPic[20]; talk_drunk(12); talk(371); clearRoom(); + // FIXME: Track 31 is missing from the soundtrack available + // from ScummVM's downloads page, so for now we're using the + // Spanish track 29 +#if 1 + playMusic(30); +#else if (_lang == kSpanish) playMusic(30); else playMusic(32); +#endif - int key = getScan(); - if (key != 0) - goto asco; - - if (_lang != kSpanish) - color_abc(kColorDarkGreen); - - loadPic("his1.alg", bgSurface, HALF_PAL); - - if (_lang == kSpanish) - black(); - - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - - if (_lang != kSpanish) - centerText(_texthis[_lang][1], 180, 180); - - updateScreen(); - - if (_lang == kSpanish) - fadeFromBlack(1); - - key = getScan(); - if (key != 0) + if (getScan() != 0) goto asco; - if (_lang == kSpanish) - _system->delayMillis(3000); - else - _system->delayMillis(4000); - - key = getScan(); - if (key != 0) - goto asco; - - fadeToBlack(1); - key = getScan(); - if (key != 0) - goto asco; + color_abc(kColorDarkGreen); - clearRoom(); - loadPic("his2.alg", bgSurface, HALF_PAL); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - - if (_lang != kSpanish) - centerText(_texthis[_lang][2], 180, 180); - - updateScreen(); - key = getScan(); - if (key != 0) - goto asco; - - if (_lang == kSpanish) - _system->delayMillis(3000); - else - _system->delayMillis(4000); - - key = getScan(); - if (key != 0) - goto asco; - - fadeToBlack(1); - key = getScan(); - if (key != 0) - goto asco; + for (int i = 1; i <= 4; i++) { + if (i < 4) + sprintf(curPic, "his%i.alg", i); + else + strcpy(curPic, "his4_2.alg"); - clearRoom(); - loadPic("his3.alg", bgSurface, HALF_PAL); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + loadPic(curPic, screenSurface, HALF_PAL); + centerText(_texthis[i], 180, 180); + updateScreen(); - if (_lang != kSpanish) - centerText(_texthis[_lang][3], 180, 180); + if (getScan() != 0) + goto asco; - updateScreen(); - key = getScan(); - if (key != 0) - goto asco; + delay(3000); - if (_lang == kSpanish) - _system->delayMillis(3000); - else - _system->delayMillis(4000); + if (i < 4) { + fadeToBlack(1); - key = getScan(); - if (key != 0) - goto asco; + if (getScan() != 0) + goto asco; - fadeToBlack(1); + clearRoom(); + } + } - clearRoom(); loadPic("his4_1.alg", bgSurface, HALF_PAL); loadPic("his4_2.alg", drawSurface3); - copyBackground(0, 0, 0, 0, 320, 200, drawSurface3, screenSurface); - - if (_lang != kSpanish) - centerText(_texthis[_lang][1], 180, 180); - - updateScreen(); - key = getScan(); - if (key != 0) - goto asco; - - if (_lang == kSpanish) - _system->delayMillis(2000); - else - _system->delayMillis(4000); - - key = getScan(); - if (key != 0) - goto asco; - for (int l = 1; l < 200; l++) { copyBackground(0, 0, 0, l, 320, 200 - l, drawSurface3, screenSurface); copyBackground(0, 200 - l, 0, 0, 320, l, bgSurface, screenSurface); updateScreen(); - key = getScan(); - if (key != 0) + if (getScan() != 0) goto asco; } @@ -1002,34 +822,24 @@ asco: stopMusic(); } -void DrasculaEngine::animation_17_2() { - talk_drunk(13); - talk_drunk(14); - flags[40] = 1; -} - -void DrasculaEngine::animation_19_2() { - talk_vonBraunpuerta(5); -} - void DrasculaEngine::animation_20_2() { - talk_vonBraunpuerta(7); - talk_vonBraunpuerta(8); + talk_vonBraun(7, kVonBraunDoor); + talk_vonBraun(8, kVonBraunDoor); talk(383); - talk_vonBraunpuerta(9); + talk_vonBraun(9, kVonBraunDoor); talk(384); - talk_vonBraunpuerta(10); + talk_vonBraun(10, kVonBraunDoor); talk(385); - talk_vonBraunpuerta(11); + talk_vonBraun(11, kVonBraunDoor); if (flags[23] == 0) { talk(350); - talk_vonBraunpuerta(57); + talk_vonBraun(57, kVonBraunDoor); } else { talk(386); - talk_vonBraunpuerta(12); + talk_vonBraun(12, kVonBraunDoor); flags[18] = 0; flags[14] = 1; - openDoor(15, 1); + toggleDoor(15, 1, kOpenDoor); exitRoom(1); animation_23_2(); exitRoom(0); @@ -1042,36 +852,32 @@ void DrasculaEngine::animation_20_2() { } } -void DrasculaEngine::animation_21_2() { - talk_vonBraunpuerta(6); -} - void DrasculaEngine::animation_23_2() { loadPic("an24.alg", frontSurface); flags[21] = 1; if (flags[25] == 0) { - talk_vonBraun(13); - talk_vonBraun(14); + talk_vonBraun(13, kVonBraunDoor); + talk_vonBraun(14, kVonBraunDoor); pause(10); talk(387); } - talk_vonBraun(15); + talk_vonBraun(15, kVonBraunNormal); placeVonBraun(42); trackVonBraun = 1; - talk_vonBraun(16); + talk_vonBraun(16, kVonBraunNormal); trackVonBraun = 2; gotoObject(157, 147); gotoObject(131, 149); trackProtagonist = 0; animation_14_2(); if (flags[25] == 0) - talk_vonBraun(17); + talk_vonBraun(17, kVonBraunNormal); pause(8); trackVonBraun = 1; - talk_vonBraun(18); + talk_vonBraun(18, kVonBraunNormal); if (flags[29] == 0) animation_23_joined(); @@ -1083,9 +889,9 @@ void DrasculaEngine::animation_23_2() { placeVonBraun(99); if (flags[29] == 0) { - talk_vonBraun(19); + talk_vonBraun(19, kVonBraunNormal); if (flags[25] == 0) { - talk_vonBraun(20); + talk_vonBraun(20, kVonBraunNormal); if (removeObject(kItemMoney) == 0) flags[30] = 1; if (removeObject(kItemTwoCoins) == 0) @@ -1093,7 +899,7 @@ void DrasculaEngine::animation_23_2() { if (removeObject(kItemOneCoin) == 0) flags[32] = 1; } - talk_vonBraun(21); + talk_vonBraun(21, kVonBraunNormal); } else animation_27_2(); @@ -1142,7 +948,7 @@ void DrasculaEngine::animation_23_joined2() { } void DrasculaEngine::animation_25_2() { - int cabinPos[6] = { 150, 6, 69, 0, 158, 161 }; + int cY = 0; loadPic("an14_2.alg", backSurface); loadPic(18, bgSurface); @@ -1152,15 +958,15 @@ void DrasculaEngine::animation_25_2() { playSound(6); for (int n = 0; n >= -160; n = n - 8) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); moveVonBraun(); - cabinPos[3] = n; + cY = n; - copyRectClip(cabinPos, backSurface, screenSurface); + copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface); updateRefresh(); updateScreen(); @@ -1174,50 +980,30 @@ void DrasculaEngine::animation_25_2() { void DrasculaEngine::animation_27_2() { flags[22] = 1; - withoutVerb(); + selectVerb(0); removeObject(kItemEarWithEarPlug); addObject(kItemEarplugs); - talk_vonBraun(23); - talk_vonBraun(24); + talk_vonBraun(23, kVonBraunNormal); + talk_vonBraun(24, kVonBraunNormal); if (flags[30] == 1) addObject(kItemMoney); if (flags[31] == 1) addObject(kItemTwoCoins); if (flags[32] == 1) addObject(kItemOneCoin); - talk_vonBraun(25); - talk_vonBraun(26); -} - -void DrasculaEngine::animation_28_2() { - for(int i = 27; i <= 30; i++) - talk_vonBraun(i); + talk_vonBraun(25, kVonBraunNormal); + talk_vonBraun(26, kVonBraunNormal); } void DrasculaEngine::animation_29_2() { if (flags[33] == 0) { - talk_vonBraun(32); - talk(398); - talk_vonBraun(33); - talk(399); - talk_vonBraun(34); - talk_vonBraun(35); - talk(400); - talk_vonBraun(36); - talk_vonBraun(37); - talk(386); - talk_vonBraun(38); - talk_vonBraun(39); - talk(401); - talk_vonBraun(40); - talk_vonBraun(41); - flags[33] = 1; + playTalkSequence(29); // sequence 29, chapter 2 } else - talk_vonBraun(43); + talk_vonBraun(43, kVonBraunNormal); talk(402); - talk_vonBraun(42); + talk_vonBraun(42, kVonBraunNormal); if (flags[38] == 0) { talk(403); @@ -1226,50 +1012,16 @@ void DrasculaEngine::animation_29_2() { talk(386); } -void DrasculaEngine::animation_30_2() { - talk_vonBraun(31); - talk(396); -} - void DrasculaEngine::animation_31_2() { - talk_vonBraun(44); + talk_vonBraun(44, kVonBraunNormal); placeVonBraun(-50); pause(15); gotoObject(159, 140); loadPic(99, backSurface); - trackProtagonist = 2; - updateRoom(); - updateScreen(); - pause(78); - trackProtagonist = 0; - updateRoom(); - updateScreen(); - pause(22); - talk(406); - placeVonBraun(98); - talk_vonBraun(45); - talk_vonBraun(46); - talk_vonBraun(47); - talk(407); - talk_vonBraun(48); - talk_vonBraun(49); - talk(408); - talk_vonBraun(50); - talk_vonBraun(51); - talk(409); - talk_vonBraun(52); - talk_vonBraun(53); - pause(12); - talk_vonBraun(54); - talk_vonBraun(55); - talk(410); - talk_vonBraun(56); - breakOut = 1; + playTalkSequence(31); // sequence 31, chapter 2 - flags[38] = 0; - flags[36] = 1; - withoutVerb(); + selectVerb(0); removeObject(kItemLeaves); removeObject(kItemBubbleGum); removeObject(kItemTissues); @@ -1293,7 +1045,7 @@ void DrasculaEngine::animation_35_2() { updateAnim(1, 70, 90, 46, 80, 6, frontSurface); updateAnim(82, 70, 90, 46, 80, 2, frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); @@ -1308,13 +1060,6 @@ void DrasculaEngine::animation_35_2() { fadeToBlack(2); } -void DrasculaEngine::animation_1_3() { - talk(413); - grr(); - pause(50); - talk(414); -} - void DrasculaEngine::animation_2_3() { flags[0] = 1; playMusic(13); @@ -1396,7 +1141,7 @@ void DrasculaEngine::animation_6_3() { for (frame = 0; frame < 6; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(yoda_x[frame], yoda_y[frame], px, py, 78, 90, frontSurface, screenSurface); updateScreen(px, py, px, py, 78, 90, screenSurface); } @@ -1436,29 +1181,6 @@ void DrasculaEngine::animation_ray() { finishSound(); } -void DrasculaEngine::animation_2_4() { - talk_igor(16, kIgorSeated); - talk(278); - talk_igor(17, kIgorSeated); - talk(279); - talk_igor(18, kIgorSeated); -} - -void DrasculaEngine::animation_3_4() { - talk_igor(19, kIgorSeated); - talk_igor(20, kIgorSeated); - talk(281); -} - -void DrasculaEngine::animation_4_4() { - talk(287); - talk_igor(21, kIgorSeated); - talk(284); - talk_igor(22, kIgorSeated); - talk(285); - talk_igor(23, kIgorSeated); -} - void DrasculaEngine::animation_7_4() { black(); talk(427); @@ -1512,37 +1234,6 @@ void DrasculaEngine::animation_1_5() { converse(8); } -void DrasculaEngine::animation_2_5() { - talk_bj(22); -} - -void DrasculaEngine::animation_3_5() { - talk_bj(23); - pickObject(10); - breakOut = 1; -} - -void DrasculaEngine::animation_4_5() { - flags[7] = 1; - updateRoom(); - updateScreen(); - talk(228); - talk_werewolf(1); - talk_werewolf(2); - pause(23); - talk(229); - talk_werewolf(3); - talk_werewolf(4); - talk(230); - talk_werewolf(5); - talk(231); - talk_werewolf(6); - talk_werewolf(7); - pause(33); - talk(232); - talk_werewolf(8); -} - void DrasculaEngine::animation_5_5(){ int h; int frame = 0; @@ -1551,7 +1242,7 @@ void DrasculaEngine::animation_5_5(){ int flyX[] = {1, 63, 125, 187, 249}; int pixelX = curX - 53, pixelY = curY - 9; - withoutVerb(); + selectVerb(0); removeObject(8); gotoObject(curX - 19, curY + curHeight); @@ -1564,7 +1255,7 @@ void DrasculaEngine::animation_5_5(){ for (frame = 0; frame < 9; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, backSurface, screenSurface); updateScreen(pixelX, pixelY, pixelX,pixelY, 97,64, screenSurface); } @@ -1574,7 +1265,7 @@ void DrasculaEngine::animation_5_5(){ for (frame = 0; frame < 9; frame++) { pause(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, frontSurface, screenSurface); updateScreen(pixelX, pixelY, pixelX,pixelY, 97, 64, screenSurface); } @@ -1618,41 +1309,6 @@ void DrasculaEngine::animation_5_5(){ loadPic(49, bgSurface, HALF_PAL); } -void DrasculaEngine::animation_6_5() { - talk_werewolf(9); - talk(234); -} - -void DrasculaEngine::animation_7_5() { - talk_werewolf(10); - talk(236); - talk_werewolf(11); - talk_werewolf(12); - talk_werewolf(13); - pause(34); - talk_werewolf(14); -} - -void DrasculaEngine::animation_8_5() { - talk_werewolf(15); - talk(238); - talk_werewolf(16); -} - -void DrasculaEngine::animation_9_5() { - flags[4] = 1; - talk(401); - withoutVerb(); - removeObject(15); -} - -void DrasculaEngine::animation_10_5() { - flags[3] = 1; - talk(401); - withoutVerb(); - removeObject(12); -} - void DrasculaEngine::animation_11_5() { flags[9] = 1; if (flags[2] == 1 && flags[3] == 1 && flags[4] == 1) @@ -1686,7 +1342,7 @@ void DrasculaEngine::animation_12_5() { updateRoom(); updateScreen(); - setDarkPalette(); + setDefaultPalette(darkPalette); for (color = 0; color < 255; color++) for (component = 0; component < 3; component++) { @@ -1742,7 +1398,7 @@ void DrasculaEngine::animation_12_5() { animate("frel.bin", 16); clearRoom(); - setBrightPalette(); + setDefaultPalette(brightPalette); setPalette((byte *)&gamePalette); flags[1] = 1; @@ -1765,7 +1421,7 @@ void DrasculaEngine::animation_12_5() { characterMoved = 0; curX = -1; objExit = 104; - withoutVerb(); + selectVerb(0); enterRoom(57); } @@ -1774,12 +1430,11 @@ void DrasculaEngine::animation_13_5() { int frame = 0; int frus_x[] = {1, 46, 91, 136, 181, 226, 271}; int frus_y[] = {1, 1, 1, 1, 1, 1, 1, 89}; - int pos_frusky[6] = { 1, 1, frank_x, 81, 44, 87 }; loadPic("auxfr.alg", backSurface); updateRoom(); - copyRectClip(pos_frusky, backSurface, screenSurface); + copyRect(1, 1, frank_x, 81, 44, 87, backSurface, screenSurface); updateScreen(); pause(15); @@ -1787,10 +1442,7 @@ void DrasculaEngine::animation_13_5() { for (;;) { updateRoom(); - pos_frusky[0] = frus_x[frame]; - pos_frusky[1] = frus_y[frame]; - pos_frusky[2] = frank_x; - copyRectClip( pos_frusky, backSurface, screenSurface); + copyRect(frus_x[frame], frus_y[frame], frank_x, 81, 44, 87, backSurface, screenSurface); updateScreen(); frank_x -= 5; frame++; @@ -1823,26 +1475,10 @@ void DrasculaEngine::animation_14_5() { trackProtagonist = 3; updateRoom(); updateScreen(); - talk_solo(_textd[_lang][18], "d18.als"); + talk_solo(_textd[18], "d18.als"); fadeToBlack(1); } -void DrasculaEngine::animation_15_5() { - talk_mus(4); - talk_mus(5); - talk_mus(6); - talk(291); - talk_mus(7); -} - -void DrasculaEngine::animation_16_5() { - talk_mus(8); -} - -void DrasculaEngine::animation_17_5() { - talk_mus(9); -} - void DrasculaEngine::animation_1_6() { trackProtagonist = 0; curX = 103; @@ -1909,36 +1545,21 @@ void DrasculaEngine::animation_1_6() { trackDrascula = 0; talk_drascula(35); - if (_lang == kSpanish) - textSurface = extraSurface; - clearRoom(); enterRoom(102); activatePendulum(); } -void DrasculaEngine::animation_2_6() { - talk_drascula(24, 1); -} - -void DrasculaEngine::animation_3_6() { - talk_drascula(24, 1); -} - -void DrasculaEngine::animation_4_6() { - talk_drascula(25, 1); -} - void DrasculaEngine::animation_5_6() { - int pos_pen[6] = { 1, 29, 204, -125, 18, 125 }; + int pY = -125; animate("man.bin", 14); for (int n = -125; n <= 0; n = n + 2) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); - pos_pen[3] = n; - copyRectClip(pos_pen, drawSurface3, screenSurface); + pY = n; + copyRect(1, 29, 204, pY, 18, 125, drawSurface3, screenSurface); updateRefresh(); @@ -1952,7 +1573,7 @@ void DrasculaEngine::animation_5_6() { void DrasculaEngine::animation_6_6() { animate("rct.bin", 11); clearRoom(); - withoutVerb(); + selectVerb(0); removeObject(20); loadPic(96, frontSurface); loadPic(97, frontSurface); @@ -1961,7 +1582,7 @@ void DrasculaEngine::animation_6_6() { doBreak = 1; objExit = 104; curX = -1; - withoutVerb(); + selectVerb(0); enterRoom(58); hare_se_ve = 1; trackProtagonist = 1; @@ -1973,11 +1594,6 @@ void DrasculaEngine::animation_6_6() { flags[2] = 1; } -void DrasculaEngine::animation_7_6() { - flags[8] = 1; - updateVisible(); -} - void DrasculaEngine::animation_9_6() { int v_cd; @@ -2014,11 +1630,11 @@ void DrasculaEngine::animation_9_6() { clearRoom(); loadPic("nota.alg", bgSurface, COMPLETE_PAL); color_abc(kColorWhite); - talk_solo(_textbj[_lang][24], "bj24.als"); - talk_solo(_textbj[_lang][25], "bj25.als"); - talk_solo(_textbj[_lang][26], "bj26.als"); - talk_solo(_textbj[_lang][27], "bj27.als"); - talk_solo(_textbj[_lang][28], "bj28.als"); + talk_solo(_textbj[24], "bj24.als"); + talk_solo(_textbj[25], "bj25.als"); + talk_solo(_textbj[26], "bj26.als"); + talk_solo(_textbj[27], "bj27.als"); + talk_solo(_textbj[28], "bj28.als"); trackProtagonist = 3; clearRoom(); loadPic(96, frontSurface, COMPLETE_PAL); @@ -2033,7 +1649,7 @@ void DrasculaEngine::animation_9_6() { copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface); updateScreen(); color_abc(kColorLightGreen); - talk_solo(_textmisc[_lang][2], "s15.als"); + talk_solo(_textmisc[2], "s15.als"); loadPic("nota2.alg", bgSurface); trackProtagonist = 0; updateRoom(); @@ -2054,54 +1670,8 @@ void DrasculaEngine::animation_9_6() { stopMusic(); } -void DrasculaEngine::animation_10_6() { - playSound(14); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - updateRefresh_pre(); - copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface); - updateScreen(); - finishSound(); - talk_bartender(23, 1); - flags[7] = 1; -} - -void DrasculaEngine::animation_11_6() { - talk_bartender(10, 1); - talk(268); - talk_bartender(11, 1); -} - -void DrasculaEngine::animation_12_6() { - talk_bartender(12, 1); - talk(270); - talk_bartender(13, 1); - talk_bartender(14, 1); -} - -void DrasculaEngine::animation_13_6() { - talk_bartender(15, 1); -} - -void DrasculaEngine::animation_14_6() { - talk_bartender(24, 1); - addObject(21); - flags[10] = 1; - breakOut = 1; -} - -void DrasculaEngine::animation_15_6() { - talk_bartender(16, 1); -} - -void DrasculaEngine::animation_18_6() { - flags[6] = 1; - withoutVerb(); - removeObject(21); - animate("beb.bin", 10); -} - void DrasculaEngine::animation_19_6() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyBackground(140, 23, 161, 69, 35, 80, drawSurface3, screenSurface); updateRefresh_pre(); @@ -2116,9 +1686,6 @@ void DrasculaEngine::animation_19_6() { } void DrasculaEngine::animation_12_2() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an12.alg", extraSurface); talk(356); @@ -2144,17 +1711,11 @@ void DrasculaEngine::animation_12_2() { talk_pianist(5); converse(1); - if (_lang == kSpanish) - textSurface = extraSurface; - flags[11] = 0; loadPic(974, extraSurface); } void DrasculaEngine::animation_26_2() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an12.alg", extraSurface); talk(392); @@ -2205,9 +1766,6 @@ void DrasculaEngine::animation_26_2() { pickObject(11); removeObject(kItemBook); - if (_lang == kSpanish) - textSurface = extraSurface; - flags[11] = 0; flags[39] = 1; loadPic(974, extraSurface); @@ -2215,23 +1773,9 @@ void DrasculaEngine::animation_26_2() { } void DrasculaEngine::animation_11_2() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an11y13.alg", extraSurface); - talk(352); - talk_bartender(1); - talk(353); - talk_bartender(17); - talk(354); - talk_bartender(18); - talk(355); - pause(40); - talk_bartender(82); - - if (_lang == kSpanish) - textSurface = extraSurface; + playTalkSequence(11); // sequence 11, chapter 2 loadPic(974, extraSurface); } @@ -2240,47 +1784,12 @@ void DrasculaEngine::animation_13_2() { loadPic("an11y13.alg", frontSurface); if (flags[41] == 0) { - talk(103); - talk_drunk(4); - flags[12] = 1; - talk(367); - talk_drunk(5); - flags[12] = 1; - talk(368); - talk_drunk(6); - talk_drunk(7); - flags[41] = 1; + playTalkSequence(13); // sequence 13, chapter 2 } - converse(2); loadPic(964, frontSurface); } -void DrasculaEngine::animation_18_2() { - talk(378); - talk_vonBraunpuerta(4); - converse(3); -} - -void DrasculaEngine::animation_22_2() { - talk(374); - - trackProtagonist=2; - updateRoom(); - updateScreen(); - playSound(13); - finishSound(); - trackProtagonist = 1; - - talk_vonBraunpuerta(1); - talk(375); - talk_vonBraunpuerta(2); - talk(376); - talk_vonBraunpuerta(3); - - flags[18] = 1; -} - void DrasculaEngine::animation_24_2() { if (curX < 178) gotoObject(208, 136); @@ -2297,7 +1806,7 @@ void DrasculaEngine::animation_24_2() { flags[21] = 1; - talk_vonBraun(22); + talk_vonBraun(22, kVonBraunNormal); if (flags[22] == 0) converse(4); @@ -2360,9 +1869,6 @@ void DrasculaEngine::animation_34_2() { } void DrasculaEngine::animation_36_2() { - if (_lang == kSpanish) - textSurface = frontSurface; - loadPic("an11y13.alg", extraSurface); talk(404); @@ -2373,9 +1879,6 @@ void DrasculaEngine::animation_36_2() { pause(40); talk_bartender(82); - if (_lang == kSpanish) - textSurface = extraSurface; - loadPic(974, extraSurface); } @@ -2387,7 +1890,7 @@ void DrasculaEngine::animation_7_2() { if (flags[3] == 1) copyBackground(258, 110, 85, 44, 23, 53, drawSurface3, bgSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); @@ -2467,17 +1970,14 @@ void DrasculaEngine::animation_5_2() { loadPic("aux5.alg", drawSurface3); flags[8] = 1; curX = curX - 4; - talk_sync(_text[_lang][46], "46.als", "4442444244244"); - withoutVerb(); + talk_sync(_text[46], "46.als", "4442444244244"); + selectVerb(0); } void DrasculaEngine::animation_6_2() { stopMusic(); flags[9] = 1; - if (_lang == kSpanish) - textSurface = frontSurface; - clearRoom(); loadPic("ciego1.alg", bgSurface, HALF_PAL); // ciego = blind loadPic("ciego2.alg", drawSurface3); @@ -2485,7 +1985,7 @@ void DrasculaEngine::animation_6_2() { loadPic("ciego4.alg", backSurface); loadPic("ciego5.alg", frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(1); @@ -2497,7 +1997,7 @@ void DrasculaEngine::animation_6_2() { pause(4); talk_hacker(67); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -2510,10 +2010,7 @@ void DrasculaEngine::animation_6_2() { loadPic(96, frontSurface); loadPic(97, extraSurface); loadPic(99, backSurface); - withoutVerb(); - - if (_lang == kSpanish) - textSurface = extraSurface; + selectVerb(0); flags[9] = 0; } @@ -2523,7 +2020,7 @@ void DrasculaEngine::animation_33_2() { flags[9] = 1; pause(12); - talk(56); + talk(60); pause(8); clearRoom(); @@ -2533,10 +2030,7 @@ void DrasculaEngine::animation_33_2() { loadPic("ciego4.alg", backSurface); loadPic("ciego5.alg", frontSurface); - if (_lang == kSpanish) - textSurface = frontSurface; - - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(10); @@ -2549,7 +2043,7 @@ void DrasculaEngine::animation_33_2() { talk_blind(10); talk_hacker(65); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); pause(14); @@ -2562,10 +2056,7 @@ void DrasculaEngine::animation_33_2() { loadPic(96, frontSurface); loadPic(97, extraSurface); loadPic(99, backSurface); - withoutVerb(); - - if (_lang == kSpanish) - textSurface = extraSurface; + selectVerb(0); flags[33] = 1; flags[9] = 0; @@ -2642,7 +2133,7 @@ void DrasculaEngine::animation_5_4(){ curY = 82; updateRoom(); updateScreen(); - openDoor(2, 0); + toggleDoor(2, 0, kOpenDoor); loadPic("auxigor.alg", frontSurface); igorX = 100; igorY = 65; @@ -2663,7 +2154,7 @@ void DrasculaEngine::animation_6_4() { loadPic(26, bgSurface, HALF_PAL); loadPic("aux26.alg", drawSurface3); loadPic("auxigor.alg", frontSurface); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); update_26_pre(); igorX = 104; igorY = 71; @@ -2676,7 +2167,7 @@ void DrasculaEngine::animation_6_4() { loadPic(96, frontSurface); loadPic(roomDisk, drawSurface3); loadPic(roomNumber, bgSurface, HALF_PAL); - withoutVerb(); + selectVerb(0); updateRoom(); } @@ -2693,12 +2184,7 @@ void DrasculaEngine::animation_8_4() { } loadPic(96, frontSurface); - openDoor(7, 2); -} - -void DrasculaEngine::animation_9_4() { - animate("st.bin", 14); - fadeToBlack(1); + toggleDoor(7, 2, kOpenDoor); } void DrasculaEngine::activatePendulum() { diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp index 1c3831e4ca..cef1a17486 100644 --- a/engines/drascula/converse.cpp +++ b/engines/drascula/converse.cpp @@ -27,38 +27,128 @@ namespace Drascula { +void DrasculaEngine::playTalkSequence(int sequence) { + bool seen = false; + + for (int i = 0; i < _talkSequencesSize; i++) { + if (_talkSequences[i].chapter == currentChapter && + _talkSequences[i].sequence == sequence) { + seen = true; + + doTalkSequenceCommand(_talkSequences[i]); + } else if (seen) // Stop searching down the list + break; + } +} + +void DrasculaEngine::doTalkSequenceCommand(TalkSequenceCommand cmd) { + switch (cmd.commandType) { + case kPause: + pause(cmd.action); + break; + case kSetFlag: + flags[cmd.action] = 1; + break; + case kClearFlag: + flags[cmd.action] = 0; + break; + case kPickObject: + pickObject(cmd.action); + break; + case kAddObject: + addObject(cmd.action); + break; + case kBreakOut: + breakOut = 1; + break; + case kConverse: + converse(cmd.action); + break; + case kPlaceVB: + placeVonBraun(cmd.action); + break; + case kUpdateRoom: + updateRoom(); + break; + case kUpdateScreen: + updateScreen(); + break; + case kTrackProtagonist: + trackProtagonist = cmd.action; + break; + case kPlaySound: + playSound(cmd.action); + break; + case kFinishSound: + finishSound(); + break; + case kTalkerGeneral: + talk(cmd.action); + break; + case kTalkerDrunk: + talk_drunk(cmd.action); + break; + case kTalkerPianist: + talk_pianist(cmd.action); + break; + case kTalkerBJ: + talk_bj(cmd.action); + break; + case kTalkerVBNormal: + talk_vonBraun(cmd.action, kVonBraunNormal); + break; + case kTalkerVBDoor: + talk_vonBraun(cmd.action, kVonBraunDoor); + break; + case kTalkerIgorSeated: + talk_igor(cmd.action, kIgorSeated); + break; + case kTalkerWerewolf: + talk_werewolf(cmd.action); + break; + case kTalkerMus: + talk_mus(cmd.action); + break; + case kTalkerDrascula: + talk_drascula(cmd.action, 1); + break; + case kTalkerBartender0: + talk_bartender(cmd.action, 0); + break; + case kTalkerBartender1: + talk_bartender(cmd.action, 1); + break; + default: + error("doTalkSequenceCommand: Unknown command: %d", cmd.commandType); + } +} + +void DrasculaEngine::cleanupString(char *string) { + uint len = strlen(string); + for (uint h = 0; h < len; h++) + if (string[h] == (char)0xa7) + string[h] = ' '; +} + void DrasculaEngine::converse(int index) { char fileName[20]; sprintf(fileName, "op_%d.cal", index); - uint h; - int game1 = 1, game2 = 1, game3 = 1, game4 = 1; - char phrase1[78]; - char phrase2[78]; - char phrase3[87]; - char phrase4[78]; - char sound1[13]; - char sound2[13]; - char sound3[13]; - char sound4[13]; - int answer1; - int answer2; - int answer3; - int used1 = 0; - int used2 = 0; - int used3 = 0; + _arj.open(fileName); + if (!_arj.isOpen()) + error("missing data file %s", fileName); + + int size = _arj.size(); + int game1 = kDialogOptionUnselected, + game2 = kDialogOptionUnselected, + game3 = kDialogOptionUnselected; + char phrase1[78], phrase2[78], phrase3[78], phrase4[78]; + char sound1[13], sound2[13], sound3[13], sound4[13]; + int answer1, answer2, answer3; char buffer[256]; - uint len; breakOut = 0; - if (currentChapter == 5) - withoutVerb(); - - _arj.open(fileName); - if (!_arj.isOpen()) { - error("missing data file %s", fileName); - } - int size = _arj.size(); + selectVerb(0); getStringFromLine(buffer, size, phrase1); getStringFromLine(buffer, size, phrase2); @@ -75,222 +165,131 @@ void DrasculaEngine::converse(int index) { _arj.close(); if (currentChapter == 2 && !strcmp(fileName, "op_5.cal") && flags[38] == 1 && flags[33] == 1) { - strcpy(phrase3, _text[_lang][405]); + strcpy(phrase3, _text[405]); strcpy(sound3, "405.als"); answer3 = 31; } if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[7] == 1) { - strcpy(phrase3, _text[_lang][273]); + strcpy(phrase3, _text[273]); strcpy(sound3, "273.als"); answer3 = 14; } if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[10] == 1) { - strcpy(phrase3, _text[_lang][274]); + strcpy(phrase3, _text[274]); strcpy(sound3, "274.als"); answer3 = 15; } - len = strlen(phrase1); - for (h = 0; h < len; h++) - if (phrase1[h] == (char)0xa7) - phrase1[h] = ' '; - - len = strlen(phrase2); - for (h = 0; h < len; h++) - if (phrase2[h] == (char)0xa7) - phrase2[h] = ' '; - - len = strlen(phrase3); - for (h = 0; h < len; h++) - if (phrase3[h] == (char)0xa7) - phrase3[h] = ' '; - - len = strlen(phrase4); - for (h = 0; h < len; h++) - if (phrase4[h] == (char)0xa7) - phrase4[h] = ' '; + cleanupString(phrase1); + cleanupString(phrase2); + cleanupString(phrase3); + cleanupString(phrase4); loadPic("car.alg", backSurface); // TODO code here should limit y position for mouse in dialog menu, - // but we can't implement this due lack backend functionality + // but we can't implement this as there is lack in backend functionality // from 1(top) to 31 color_abc(kColorLightGreen); while (breakOut == 0) { updateRoom(); - if (currentChapter == 1 || currentChapter == 4 || currentChapter == 6) { - if (musicStatus() == 0 && flags[11] == 0) - playMusic(roomMusic); - } else if (currentChapter == 2) { - if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0) - playMusic(roomMusic); - } else if (currentChapter == 3 || currentChapter == 5) { - if (musicStatus() == 0) + if (musicStatus() == 0 && roomMusic != 0) { + if (currentChapter == 3 || currentChapter == 5) { playMusic(roomMusic); + } else { // chapters 1, 2, 4, 6 + if (flags[11] == 0) + playMusic(roomMusic); + } } updateEvents(); + print_abc_opc(phrase1, 2, game1); + print_abc_opc(phrase2, 10, game2); + print_abc_opc(phrase3, 18, game3); + print_abc_opc(phrase4, 26, kDialogOptionUnselected); + if (mouseY > 0 && mouseY < 9) { - if (used1 == 1 && _color != kColorWhite) + if (game1 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); - else if (used1 == 0 && _color != kColorLightGreen) + else if (game1 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); + + print_abc_opc(phrase1, 2, kDialogOptionSelected); + + if (leftMouseButton == 1) { + delay(100); + game1 = kDialogOptionClicked; + talk(phrase1, sound1); + response(answer1); + } } else if (mouseY > 8 && mouseY < 17) { - if (used2 == 1 && _color != kColorWhite) + if (game2 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); - else if (used2 == 0 && _color != kColorLightGreen) + else if (game2 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); + + print_abc_opc(phrase2, 10, kDialogOptionSelected); + + if (leftMouseButton == 1) { + delay(100); + game2 = kDialogOptionClicked; + talk(phrase2, sound2); + response(answer2); + } } else if (mouseY > 16 && mouseY < 25) { - if (used3 == 1 && _color != kColorWhite) + if (game3 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); - else if (used3 == 0 && _color != kColorLightGreen) + else if (game3 != kDialogOptionClicked && _color != kColorLightGreen) color_abc(kColorLightGreen); - } else if (_color != kColorLightGreen) - color_abc(kColorLightGreen); - if (mouseY > 0 && mouseY < 9) - game1 = 2; - else if (mouseY > 8 && mouseY < 17) - game2 = 2; - else if (mouseY > 16 && mouseY < 25) - game3 = 2; - else if (mouseY > 24 && mouseY < 33) - game4 = 2; + print_abc_opc(phrase3, 18, kDialogOptionSelected); - print_abc_opc(phrase1, 1, 2, game1); - print_abc_opc(phrase2, 1, 10, game2); - print_abc_opc(phrase3, 1, 18, game3); - print_abc_opc(phrase4, 1, 26, game4); - - updateScreen(); - - if ((leftMouseButton == 1) && (game1 == 2)) { - delay(100); - used1 = 1; - talk(phrase1, sound1); - if (currentChapter == 3) - grr(); - else - response(answer1); - } else if ((leftMouseButton == 1) && (game2 == 2)) { - delay(100); - used2 = 1; - talk(phrase2, sound2); - if (currentChapter == 3) - grr(); - else - response(answer2); - } else if ((leftMouseButton == 1) && (game3 == 2)) { - delay(100); - used3 = 1; - talk(phrase3, sound3); - if (currentChapter == 3) - grr(); - else + if (leftMouseButton == 1) { + delay(100); + game3 = kDialogOptionClicked; + talk(phrase3, sound3); response(answer3); - } else if ((leftMouseButton == 1) && (game4 == 2)) { - delay(100); - talk(phrase4, sound4); - breakOut = 1; - } + } + } else if (mouseY > 24 && mouseY < 33) { + print_abc_opc(phrase4, 26, kDialogOptionSelected); - if (leftMouseButton == 1) { - delay(100); + if (leftMouseButton == 1) { + delay(100); + talk(phrase4, sound4); + breakOut = 1; + } + } else if (_color != kColorLightGreen) color_abc(kColorLightGreen); - } - game1 = (used1 == 0) ? 1 : 3; - game2 = (used2 == 0) ? 1 : 3; - game3 = (used3 == 0) ? 1 : 3; - game4 = 1; + updateScreen(); } // while (breakOut == 0) if (currentChapter == 2) loadPic(menuBackground, backSurface); else loadPic(99, backSurface); - if (currentChapter != 5) - withoutVerb(); } void DrasculaEngine::response(int function) { - if (currentChapter == 1) { - if (function >= 10 && function <= 12) - talk_drunk(function - 9); - } else if (currentChapter == 2) { - if (function == 8) - animation_8_2(); - else if (function == 9) - animation_9_2(); - else if (function == 10) - animation_10_2(); - else if (function == 15) - animation_15_2(); - else if (function == 16) + playTalkSequence(function); + + if (currentChapter == 2) { + if (function == 16) animation_16_2(); - else if (function == 17) - animation_17_2(); - else if (function == 19) - animation_19_2(); else if (function == 20) animation_20_2(); - else if (function == 21) - animation_21_2(); else if (function == 23) animation_23_2(); - else if (function == 28) - animation_28_2(); else if (function == 29) animation_29_2(); - else if (function == 30) - animation_30_2(); else if (function == 31) animation_31_2(); - } else if (currentChapter == 4) { - if (function == 2) - animation_2_4(); - else if (function == 3) - animation_3_4(); - else if (function == 4) - animation_4_4(); - } else if (currentChapter == 5) { - if (function == 2) - animation_2_5(); - else if (function == 3) - animation_3_5(); - else if (function == 6) - animation_6_5(); - else if (function == 7) - animation_7_5(); - else if (function == 8) - animation_8_5(); - else if (function == 15) - animation_15_5(); - else if (function == 16) - animation_16_5(); - else if (function == 17) - animation_17_5(); - } else if (currentChapter == 6) { - if (function == 2) - animation_2_6(); - else if (function == 3) - animation_3_6(); - else if (function == 4) - animation_4_6(); - else if (function == 11) - animation_11_6(); - else if (function == 12) - animation_12_6(); - else if (function == 13) - animation_13_6(); - else if (function == 14) - animation_14_6(); - else if (function == 15) - animation_15_6(); + } else if (currentChapter == 3) { + grr(); } } diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index 9832d58294..81c8d9a62a 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -218,7 +218,7 @@ static const DrasculaGameDescription gameDescriptions[] = { 0, { {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563}, - {"packet.005", 0, "f80e10e37000a2201eabf8dad82c7f64", 16184223}, + {"packet.005", 0, "58caac54b891f5d7f335e710e45e5d29", 16209623}, {NULL, 0, NULL, 0} }, Common::IT_ITA, diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 2d24978f21..c1449ea2c9 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -65,7 +65,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam if (cd_num >= 0) _system->openCD(cd_num); - _lang = 0; + _lang = kEnglish; } DrasculaEngine::~DrasculaEngine() { @@ -86,6 +86,7 @@ DrasculaEngine::~DrasculaEngine() { free(_roomPreUpdates); free(_roomUpdates); free(_roomActions); + free(_talkSequences); freeTexts(_text); freeTexts(_textd); freeTexts(_textb); @@ -112,23 +113,23 @@ int DrasculaEngine::init() { switch (getLanguage()) { case Common::EN_ANY: - _lang = 0; + _lang = kEnglish; break; case Common::ES_ESP: - _lang = 1; + _lang = kSpanish; break; case Common::DE_DEU: - _lang = 2; + _lang = kGerman; break; case Common::FR_FRA: - _lang = 3; + _lang = kFrench; break; case Common::IT_ITA: - _lang = 4; + _lang = kItalian; break; default: warning("Unknown game language. Falling back to English"); - _lang = 0; + _lang = kEnglish; } _charMap = 0; @@ -179,7 +180,9 @@ int DrasculaEngine::init() { int DrasculaEngine::go() { currentChapter = 1; // values from 1 to 6 will start each part of game - hay_que_load = 0; + loadedDifferentChapter = 0; + + checkCD(); for (;;) { int i; @@ -199,7 +202,6 @@ int DrasculaEngine::go() { talkHeight = TALK_HEIGHT; talkWidth = TALK_WIDTH; hasAnswer = 0; savedTime = 0; - changeColor = 0; breakOut = 0; vonBraunX = 120; trackVonBraun = 1; vonBraunHasMoved = 0; framesWithoutAction = 0; @@ -221,50 +223,46 @@ int DrasculaEngine::go() { withVoices = 0; selectionMade = 0; - if (currentChapter != 6) - loadPic(95, tableSurface); + if (currentChapter != 3) + loadPic(96, frontSurface, COMPLETE_PAL); if (currentChapter == 1) { - loadPic(96, frontSurface, COMPLETE_PAL); - loadPic(99, backSurface); - loadPic(97, extraSurface); } else if (currentChapter == 2) { - loadPic(96, frontSurface, COMPLETE_PAL); loadPic("pts.alg", drawSurface2); } else if (currentChapter == 3) { loadPic("aux13.alg", bgSurface, COMPLETE_PAL); loadPic(96, frontSurface); - loadPic(97, extraSurface); - loadPic(99, backSurface); } else if (currentChapter == 4) { - loadPic(96, frontSurface, COMPLETE_PAL); - if (hay_que_load == 0) + if (loadedDifferentChapter == 0) animation_ray(); loadPic(96, frontSurface); clearRoom(); - loadPic(99, backSurface); - loadPic(97, extraSurface); } else if (currentChapter == 5) { - loadPic(96, frontSurface, COMPLETE_PAL); - loadPic(97, extraSurface); - loadPic(99, backSurface); } else if (currentChapter == 6) { igorX = 105, igorY = 85, trackIgor = 1; drasculaX = 62, drasculaY = 99, trackDrascula = 1; actorFrames[kFramePendulum] = 0; flag_tv = 0; + } - loadPic(96, frontSurface, COMPLETE_PAL); + loadPic(95, tableSurface); + for (i = 0; i < 25; i++) + memcpy(crosshairCursor + i * 40, tableSurface + 225 + (56 + i) * 320, 40); + + if (_lang == kSpanish) + loadPic(974, tableSurface); + + if (currentChapter != 2) { loadPic(99, backSurface); loadPic(97, extraSurface); - loadPic(95, tableSurface); } + memset(iconName, 0, sizeof(iconName)); for (i = 0; i < 6; i++) - strcpy(iconName[i + 1], _textverbs[_lang][i]); + strcpy(iconName[i + 1], _textverbs[i]); - assignDefaultPalette(); + assignPalette(defaultPalette); if (!runCurrentChapter()) { endChapter(); break; @@ -294,11 +292,6 @@ bool DrasculaEngine::runCurrentChapter() { rightMouseButton = 0; - if (_lang == kSpanish) - textSurface = extraSurface; - else - textSurface = tableSurface; - previousMusic = -1; if (currentChapter != 2) { @@ -327,14 +320,14 @@ bool DrasculaEngine::runCurrentChapter() { if (currentChapter == 1) { pickObject(28); - if (hay_que_load == 0) + if (loadedDifferentChapter == 0) animation_1_1(); - withoutVerb(); + selectVerb(0); loadPic("2aux62.alg", drawSurface2); trackProtagonist = 1; objExit = 104; - if (hay_que_load != 0) { + if (loadedDifferentChapter != 0) { if (!loadGame(saveName)) { return true; } @@ -348,7 +341,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(kItemPhone); trackProtagonist = 3; objExit = 162; - if (hay_que_load == 0) + if (loadedDifferentChapter == 0) enterRoom(14); else { if (!loadGame(saveName)) { @@ -366,7 +359,7 @@ bool DrasculaEngine::runCurrentChapter() { flags[1] = 1; trackProtagonist = 1; objExit = 99; - if (hay_que_load == 0) + if (loadedDifferentChapter == 0) enterRoom(20); else { if (!loadGame(saveName)) { @@ -380,7 +373,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(kItemReefer2); addObject(kItemOneCoin2); objExit = 100; - if (hay_que_load == 0) { + if (loadedDifferentChapter == 0) { enterRoom(21); trackProtagonist = 0; curX = 235; @@ -402,7 +395,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(20); trackProtagonist = 1; objExit = 100; - if (hay_que_load == 0) { + if (loadedDifferentChapter == 0) { enterRoom(45); } else { if (!loadGame(saveName)) { @@ -415,7 +408,7 @@ bool DrasculaEngine::runCurrentChapter() { trackProtagonist = 1; objExit = 104; - if (hay_que_load == 0) { + if (loadedDifferentChapter == 0) { enterRoom(58); animation_1_6(); } else { @@ -426,6 +419,8 @@ bool DrasculaEngine::runCurrentChapter() { } } + showCursor(); + while (1) { if (characterMoved == 0) { stepX = STEP_X; @@ -444,7 +439,8 @@ bool DrasculaEngine::runCurrentChapter() { // made the character start walking off screen, as his actual position was // different than the displayed one if (roomNumber == 3 && (curX == 279) && (curY + curHeight == 101)) { - animation_1_2(); + gotoObject(178, 121); + gotoObject(169, 135); } else if (roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) { walkToObject = 1; gotoObject(190, 130); @@ -485,6 +481,7 @@ bool DrasculaEngine::runCurrentChapter() { #else if (rightMouseButton == 1 && menuScreen == 1) { #endif + delay(100); if (currentChapter == 2) loadPic(menuBackground, backSurface); else @@ -502,8 +499,14 @@ bool DrasculaEngine::runCurrentChapter() { } else { #else } - if (rightMouseButton == 1 && menuScreen == 0) { + + // Do not show the inventory screen in chapter 5, if the right mouse button is clicked + // while the plug (object 16) is held + // Fixes bug #2059621 - "DRASCULA: Plug bug" + if (rightMouseButton == 1 && menuScreen == 0 && + !(currentChapter == 5 && pickedObject == 16)) { #endif + delay(100); characterMoved = 0; if (trackProtagonist == 2) trackProtagonist = 1; @@ -519,12 +522,14 @@ bool DrasculaEngine::runCurrentChapter() { #ifndef _WIN32_WCE updateEvents(); #endif - withoutVerb(); + selectVerb(0); } if (leftMouseButton == 1 && menuBar == 1) { + delay(100); selectVerbFromBar(); } else if (leftMouseButton == 1 && takeObject == 0) { + delay(100); if (verify1()) return true; } else if (leftMouseButton == 1 && takeObject == 1) { @@ -553,15 +558,15 @@ bool DrasculaEngine::runCurrentChapter() { if (!saveLoadScreen()) return true; } else if (key == Common::KEYCODE_F8) { - withoutVerb(); + selectVerb(0); } else if (key == Common::KEYCODE_v) { withVoices = 1; - print_abc(_textsys[_lang][2], 96, 86); + print_abc(_textsys[2], 96, 86); updateScreen(); delay(1410); } else if (key == Common::KEYCODE_t) { withVoices = 0; - print_abc(_textsys[_lang][3], 94, 86); + print_abc(_textsys[3], 94, 86); updateScreen(); delay(1460); } else if (key == Common::KEYCODE_ESCAPE) { @@ -593,8 +598,10 @@ char *DrasculaEngine::getLine(char *buf, int len) { for (;;) { b = buf; - while (!_arj.eos()) { + while (true) { c = ~_arj.readByte(); + if (_arj.eos()) break; + if (c == '\r') continue; if (c == '\n' || b - buf >= (len - 1)) @@ -702,14 +709,14 @@ void DrasculaEngine::updateEvents() { Common::Event event; Common::EventManager *eventMan = _system->getEventManager(); - AudioCD.updateCD(); + updateMusic(); #ifdef _WIN32_WCE if (eventMan->pollEvent(event)) { #else while (eventMan->pollEvent(event)) { #endif - switch (event.type) { + switch (event.type) { case Common::EVENT_KEYDOWN: _keyPressed = event.kbd; break; @@ -759,7 +766,6 @@ void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int w float totalX, totalY; int n, m; float pixelX, pixelY; - int pixelPos[6]; newWidth = (width * factor) / 100; newHeight = (height * factor) / 100; @@ -772,14 +778,8 @@ void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int w for (n = 0; n < newHeight; n++) { for (m = 0; m < newWidth; m++) { - pixelPos[0] = (int)pixelX; - pixelPos[1] = (int)pixelY; - pixelPos[2] = xx2 + m; - pixelPos[3] = yy2 + n; - pixelPos[4] = 1; - pixelPos[5] = 1; - - copyRectClip(pixelPos, dir_inicio, dir_fin); + copyRect((int)pixelX, (int)pixelY, xx2 + m, yy2 + n, + 1, 1, dir_inicio, dir_fin); pixelX += totalX; } @@ -796,7 +796,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){ do { counter--; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (currentChapter == 3) updateScreen(0, 0, 0, y, 320, 200, screenSurface); else @@ -820,7 +820,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){ } } while (counter > 0); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } @@ -965,6 +965,15 @@ bool DrasculaEngine::loadDrasculaDat() { _roomActions[i].speechID = in.readSint16BE(); } + _talkSequencesSize = in.readUint16BE(); + _talkSequences = (TalkSequenceCommand *)malloc(sizeof(TalkSequenceCommand) * _talkSequencesSize); + for (i = 0; i < _talkSequencesSize; i++) { + _talkSequences[i].chapter = in.readSint16BE(); + _talkSequences[i].sequence = in.readSint16BE(); + _talkSequences[i].commandType = in.readSint16BE(); + _talkSequences[i].action = in.readSint16BE(); + } + _numLangs = in.readUint16BE(); _text = loadTexts(in); @@ -986,24 +995,22 @@ bool DrasculaEngine::loadDrasculaDat() { return true; } -char ***DrasculaEngine::loadTexts(Common::File &in) { +char **DrasculaEngine::loadTexts(Common::File &in) { int numTexts = in.readUint16BE(); - char ***res; + char **res = (char **)malloc(sizeof(char *) * numTexts); int entryLen; - char *pos; + char *pos = 0; int len; - res = (char ***)malloc(sizeof(char *) * _numLangs); - for (int lang = 0; lang < _numLangs; lang++) { entryLen = in.readUint16BE(); - - res[lang] = (char **)malloc(sizeof(char *) * numTexts); - pos = (char *)malloc(entryLen); - res[lang][0] = pos; - - in.read(res[lang][0], entryLen); + if (lang == _lang) { + res[0] = pos; + in.read(res[0], entryLen); + } else { + in.read(pos, entryLen); + } pos += DATAALIGNMENT; @@ -1013,23 +1020,19 @@ char ***DrasculaEngine::loadTexts(Common::File &in) { len = READ_BE_UINT16(pos); pos += 2 + len; - res[lang][i] = pos; + if (lang == _lang) + res[i] = pos; } } return res; } -void DrasculaEngine::freeTexts(char ***ptr) { +void DrasculaEngine::freeTexts(char **ptr) { if (!ptr) return; - for (int lang = 0; lang < _numLangs; lang++) { - if (ptr[lang]) { - free(ptr[lang][0]); - free(ptr[lang]); - } - } + free(ptr[0]); free(ptr); } diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index 8bb73d8dd1..3b499f27a0 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -37,16 +37,13 @@ #include "common/keyboard.h" #include "common/unarj.h" -#include "sound/audiostream.h" #include "sound/mixer.h" -#include "sound/voc.h" -#include "sound/audiocd.h" #include "engines/engine.h" namespace Drascula { -#define DRASCULA_DAT_VER 2 +#define DRASCULA_DAT_VER 4 #define DATAALIGNMENT 4 enum DrasculaGameFeatures { @@ -135,6 +132,11 @@ enum IgorTalkerTypes { kIgorWig = 4 }; +enum VonBraunTalkerTypes { + kVonBraunNormal = 0, + kVonBraunDoor = 1 +}; + enum AnimFrameTypes { kFrameBlind = 0, kFrameSnore = 1, @@ -146,6 +148,64 @@ enum AnimFrameTypes { kFramePendulum = 7 }; +enum DialogOptionStatus { + kDialogOptionUnselected = 1, + kDialogOptionSelected = 2, + kDialogOptionClicked = 3 +}; + +enum TalkSequenceCommands { + kPause = 0, + kSetFlag = 1, + kClearFlag = 2, + kPickObject = 3, + kAddObject = 4, + kBreakOut = 5, + kConverse = 6, + kPlaceVB = 7, + kUpdateRoom = 8, + kUpdateScreen = 9, + kTrackProtagonist = 10, + kPlaySound = 11, + kFinishSound = 12, + kTalkerGeneral = 13, + kTalkerDrunk = 14, + kTalkerPianist = 15, + kTalkerBJ = 16, + kTalkerVBNormal = 17, + kTalkerVBDoor = 18, + kTalkerIgorSeated = 19, + kTalkerWerewolf = 20, + kTalkerMus = 21, + kTalkerDrascula = 22, + kTalkerBartender0 = 23, + kTalkerBartender1 = 24 +}; + +enum CharacterDirections { + kDirectionUp = 0, + kDirectionDown = 1, + kDirectionLeft = 2, + kDirectionRight = 3 +}; + +enum MouseCursors { + kCursorCrosshair = 0, + kCursorCurrentItem = 1 +}; + +enum DoorActions { + kCloseDoor = 0, + kOpenDoor = 1 +}; + +struct TalkSequenceCommand { + int chapter; + int sequence; + int commandType; + int action; +}; + #define TEXTD_START 68 struct DrasculaGameDescription; @@ -248,13 +308,18 @@ public: typedef signed char DacPalette256[256][3]; void setRGB(byte *pal, int plt); - void assignDefaultPalette(); + void assignPalette(DacPalette256 pal); + void setDefaultPalette(DacPalette256 pal); void setPalette(byte *PalBuf); void copyBackground(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest); + + void copyBackground() { + copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + } + void copyRect(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest); - void copyRectClip(int *Array, byte *src, byte *dest); void updateScreen() { updateScreen(0, 0, 0, 0, 320, 200, screenSurface); } @@ -275,6 +340,9 @@ public: DacPalette256 brightPalette; DacPalette256 darkPalette; + byte *crosshairCursor; + byte *mouseCursor; + // Graphics buffers/pointers byte *VGA; byte *bgSurface; @@ -309,7 +377,7 @@ public: int roomObjX[40], roomObjY[40], trackObj[40]; int inventoryObjects[43]; char _targetSurface[40][20]; - int _destX[40], _destY[40], trackCharacter_alkeva[40], alapuertakeva[40]; + int _destX[40], _destY[40], trackCharacter_alkeva[40], roomExits[40]; int x1[40], y1[40], x2[40], y2[40]; int takeObject, pickedObject; int withVoices; @@ -321,7 +389,8 @@ public: int flags[NUM_FLAGS]; int frame_y; - int curX, curY, characterMoved, curDirection, trackProtagonist, num_frame, hare_se_ve; + int curX, curY, characterMoved, curDirection, trackProtagonist, num_frame; + int hare_se_ve; // TODO: what is this for? int roomX, roomY, checkFlags; int doBreak; int stepX, stepY; @@ -334,7 +403,6 @@ public: int timeDiff, startTime; int hasAnswer; int savedTime; - int changeColor; int breakOut; int vonBraunX, trackVonBraun, vonBraunHasMoved; float newHeight, newWidth; @@ -347,7 +415,7 @@ public: int framesWithoutAction; int term_int; int currentChapter; - int hay_que_load; + int loadedDifferentChapter; char saveName[13]; int _color; int musicStopped; @@ -368,12 +436,9 @@ public: void moveVonBraun(); void placeVonBraun(int pointX); void hipo_sin_nadie(int counter); - void openDoor(int nflag, int doorNum); + void toggleDoor(int nflag, int doorNum, int action); void showMap(); - void setDarkPalette(); - - void withoutVerb(); void enterRoom(int); void clearRoom(); void gotoObject(int, int); @@ -399,6 +464,7 @@ public: void fadeToBlack(int fadeSpeed); signed char adjustToVGA(signed char value); void color_abc(int cl); + bool textFitsCentered(char *text, int x); void centerText(const char *,int,int); void playSound(int soundNum); bool animate(const char *animation, int FPS); @@ -408,7 +474,7 @@ public: void placeDrascula(); void talkInit(const char *filename); - bool isTalkFinished(int* length); + bool isTalkFinished(); void talk_igor(int, int); void talk_drascula(int index, int talkerType = 0); void talk_solo(const char *, const char *); @@ -417,7 +483,7 @@ public: void talk_bj_bed(int); void talk_htel(int); void talk_bj(int); - void talk_baul(int); + void talk_trunk(int); void talk(int); void talk(const char *, const char *); void talk_sync(const char *, const char *, const char *); @@ -425,9 +491,8 @@ public: void talk_pianist(int); void talk_werewolf(int); void talk_mus(int); - void talk_dr_grande(int); - void talk_vonBraun(int); - void talk_vonBraunpuerta(int); + void talk_drascula_big(int); + void talk_vonBraun(int, int); void talk_blind(int); void talk_hacker(int); void talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface); @@ -435,18 +500,14 @@ public: void hiccup(int); void finishSound(); void stopSound(); - void closeDoor(int nflag, int doorNum); void playMusic(int p); void stopMusic(); + void updateMusic(); int musicStatus(); void updateRoom(); bool loadGame(const char *); void updateDoor(int); - void setDefaultPalette(); void setPaletteBase(int darkness); - void assignBrightPalette(); - void assignDarkPalette(); - void setBrightPalette(); void updateVisible(); void startWalking(); void updateRefresh(); @@ -458,7 +519,10 @@ public: bool exitRoom(int); bool pickupObject(); bool checkAction(int); - void setCursorTable(); + void setCursor(int cursor); + void showCursor(); + void hideCursor(); + bool isCursorVisible(); void enterName(); bool soundIsActive(); void waitFrameSSN(); @@ -490,8 +554,11 @@ public: bool checkMenuFlags(); void setupRoomsTable(); bool roomParse(int, int); + void cleanupString(char *string); + void playTalkSequence(int sequence); + void doTalkSequenceCommand(TalkSequenceCommand cmd); void converse(int); - void print_abc_opc(const char *, int, int, int); + void print_abc_opc(const char *, int, int); void response(int); void activatePendulum(); @@ -551,28 +618,17 @@ public: void animation_3_1(); void animation_4_1(); // - void animation_1_2(); void animation_2_2(); - void animation_3_2(); void animation_4_2(); void animation_5_2(); void animation_6_2(); void animation_7_2(); - void animation_8_2(); - void animation_9_2(); - void animation_10_2(); void animation_11_2(); void animation_12_2(); void animation_13_2(); void animation_14_2(); - void animation_15_2(); void animation_16_2(); - void animation_17_2(); - void animation_18_2(); - void animation_19_2(); void animation_20_2(); - void animation_21_2(); - void animation_22_2(); void animation_23_2(); void animation_23_joined(); void animation_23_joined2(); @@ -580,9 +636,7 @@ public: void animation_25_2(); void animation_26_2(); void animation_27_2(); - void animation_28_2(); void animation_29_2(); - void animation_30_2(); void animation_31_2(); void animation_32_2(); void animation_33_2(); @@ -590,7 +644,6 @@ public: void animation_35_2(); void animation_36_2(); // - void animation_1_3(); void animation_2_3(); void animation_3_3(); void animation_4_3(); @@ -599,48 +652,22 @@ public: void animation_ray(); // void animation_1_4(); - void animation_2_4(); - void animation_3_4(); - void animation_4_4(); void animation_5_4(); void animation_6_4(); void animation_7_4(); void animation_8_4(); - void animation_9_4(); // void animation_1_5(); - void animation_2_5(); - void animation_3_5(); - void animation_4_5(); void animation_5_5(); - void animation_6_5(); - void animation_7_5(); - void animation_8_5(); - void animation_9_5(); - void animation_10_5(); void animation_11_5(); void animation_12_5(); void animation_13_5(); void animation_14_5(); - void animation_15_5(); - void animation_16_5(); - void animation_17_5(); // void animation_1_6(); - void animation_2_6(); - void animation_3_6(); - void animation_4_6(); void animation_5_6(); void animation_6_6(); - void animation_7_6(); void animation_9_6(); - void animation_10_6(); - void animation_11_6(); - void animation_12_6(); - void animation_13_6(); - void animation_14_6(); - void animation_15_6(); - void animation_18_6(); void animation_19_6(); void update_1_pre(); @@ -683,23 +710,24 @@ private: int _roomPreUpdatesSize; int _roomUpdatesSize; int _roomActionsSize; + int _talkSequencesSize; int _numLangs; - char ***_text; - char ***_textd; - char ***_textb; - char ***_textbj; - char ***_texte; - char ***_texti; - char ***_textl; - char ***_textp; - char ***_textt; - char ***_textvb; - char ***_textsys; - char ***_texthis; - char ***_textverbs; - char ***_textmisc; - char ***_textd1; + char **_text; + char **_textd; + char **_textb; + char **_textbj; + char **_texte; + char **_texti; + char **_textl; + char **_textp; + char **_textt; + char **_textvb; + char **_textsys; + char **_texthis; + char **_textverbs; + char **_textmisc; + char **_textd1; ItemLocation *_itemLocations; int *_polX, *_polY; int *_verbBarX; @@ -709,9 +737,10 @@ private: int *_pianistX, *_drunkX; RoomUpdate *_roomPreUpdates, *_roomUpdates; RoomTalkAction *_roomActions; + TalkSequenceCommand *_talkSequences; - char ***loadTexts(Common::File &in); - void freeTexts(char ***ptr); + char **loadTexts(Common::File &in); + void freeTexts(char **ptr); }; } // End of namespace Drascula diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 67993bfb6c..de35de5ab2 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -47,6 +47,10 @@ void DrasculaEngine::allocMemory() { assert(tableSurface); extraSurface = (byte *)malloc(64000); assert(extraSurface); + crosshairCursor = (byte *)malloc(40 * 25); + assert(crosshairCursor); + mouseCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT); + assert(mouseCursor); } void DrasculaEngine::freeMemory() { @@ -58,10 +62,12 @@ void DrasculaEngine::freeMemory() { free(drawSurface3); free(extraSurface); free(frontSurface); + free(crosshairCursor); + free(mouseCursor); } void DrasculaEngine::moveCursor() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); moveCharacters(); @@ -78,14 +84,6 @@ void DrasculaEngine::moveCursor() { showMenu(); else if (menuBar == 1) clearMenu(); - - int cursorPos[6] = { 0, 0, mouseX - 20, mouseY - 17, OBJWIDTH, OBJHEIGHT }; - copyRectClip(cursorPos, drawSurface3, screenSurface); -} - -void DrasculaEngine::setCursorTable() { - int cursorPos[6] = { 225, 56, mouseX - 20, mouseY - 12, 40, 25 }; - copyRectClip(cursorPos, tableSurface, screenSurface); } void DrasculaEngine::loadPic(const char *NamePcc, byte *targetSurface, int colorCount) { @@ -148,7 +146,15 @@ void DrasculaEngine::copyBackground(int xorg, int yorg, int xdes, int ydes, int int height, byte *src, byte *dest) { dest += xdes + ydes * 320; src += xorg + yorg * 320; + /* Unoptimized code for (int x = 0; x < height; x++) { + memcpy(dest + 320 * x, src + 320 * x, width); + } */ + + // A bit more optimized code, thanks to Fingolfin + // Uses 2 less registers and performs 2 less multiplications + int x = height; + while (x--) { memcpy(dest, src, width); dest += 320; src += 320; @@ -159,24 +165,7 @@ void DrasculaEngine::copyRect(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *src, byte *dest) { int y, x; - dest += xdes + ydes * 320; - src += xorg + yorg * 320; - - for (y = 0; y < height; y++) - for (x = 0; x < width; x++) - if (src[x + y * 320] != 255) - dest[x + y * 320] = src[x + y * 320]; -} - -void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) { - int y, x; - int xorg = Array[0]; - int yorg = Array[1]; - int xdes = Array[2]; - int ydes = Array[3]; - int width = Array[4]; - int height = Array[5]; - + // if (ydes < 0) { yorg += -ydes; height += ydes; @@ -191,6 +180,7 @@ void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) { width -= (xdes + width) - 320; if ((ydes + height) > 199) height -= (ydes + height) - 200; + // dest += xdes + ydes * 320; src += xorg + yorg * 320; @@ -202,16 +192,7 @@ void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) { } void DrasculaEngine::updateScreen(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *buffer) { - byte *ptr = VGA; - - ptr += xdes + ydes * 320; - buffer += xorg + yorg * 320; - for (int x = 0; x < height; x++) { - memcpy(ptr, buffer, width); - ptr += 320; - buffer += 320; - } - + copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, VGA); _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); _system->updateScreen(); } @@ -229,22 +210,22 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) { letterX = _charMap[i].mappedChar; switch (_charMap[i].charType) { - case 0: // letters - letterY = (_lang == kSpanish) ? 149 : 158; - break; - case 1: // signs - letterY = (_lang == kSpanish) ? 160 : 169; - break; - case 2: // accented - letterY = 180; - break; + case 0: // letters + letterY = (_lang == kSpanish) ? 149 : 158; + break; + case 1: // signs + letterY = (_lang == kSpanish) ? 160 : 169; + break; + case 2: // accented + letterY = 180; + break; } // switch break; } // if } // for - int textPos[6] = { letterX, letterY, screenX, screenY, CHAR_WIDTH, CHAR_HEIGHT }; - copyRectClip(textPos, textSurface, screenSurface); + copyRect(letterX, letterY, screenX, screenY, + CHAR_WIDTH, CHAR_HEIGHT, tableSurface, screenSurface); screenX = screenX + CHAR_WIDTH; if (screenX > 317) { @@ -254,10 +235,12 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) { } // for } -void DrasculaEngine::print_abc_opc(const char *said, int screenX, int screenY, int game) { +void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) { int signY, letterY, letterX = 0; uint len = strlen(said); + int screenX = 1; + for (uint h = 0; h < len; h++) { if (game == 1) { letterY = 6; @@ -293,76 +276,70 @@ void DrasculaEngine::print_abc_opc(const char *said, int screenX, int screenY, i } // if } // for - int textPos[6] = { letterX, letterY, screenX, screenY, CHAR_WIDTH_OPC, CHAR_HEIGHT_OPC }; - copyRectClip(textPos, backSurface, screenSurface); + copyRect(letterX, letterY, screenX, screenY, + CHAR_WIDTH_OPC, CHAR_HEIGHT_OPC, backSurface, screenSurface); screenX = screenX + CHAR_WIDTH_OPC; } } -void DrasculaEngine::centerText(const char *message, int textX, int textY) { - char bb[200], m2[200], m1[200], mb[10][50]; - char m3[200]; - int h, fil, textX3, textX2, textX1, conta_f = 0, ya = 0; - - strcpy(m1, " "); - strcpy(m2, " "); - strcpy(m3, " "); - strcpy(bb, " "); - - for (h = 0; h < 10; h++) - strcpy(mb[h], " "); - - if (textX > 160) - ya = 1; - - strcpy(m1, message); - textX = CLIP<int>(textX, 60, 255); - - textX1 = textX; - - if (ya == 1) - textX1 = 315 - textX; - - textX2 = (strlen(m1) / 2) * CHAR_WIDTH; - - while (true) { - strcpy(bb, m1); - scumm_strrev(bb); - - if (textX1 < textX2) { - strcpy(m3, strrchr(m1, ' ')); - strcpy(m1, strstr(bb, " ")); - scumm_strrev(m1); - m1[strlen(m1) - 1] = '\0'; - strcat(m3, m2); - strcpy(m2, m3); - }; - - textX2 = (strlen(m1) / 2) * CHAR_WIDTH; - - if (textX1 < textX2) - continue; +bool DrasculaEngine::textFitsCentered(char *text, int x) { + int len = strlen(text); + int tmp = CLIP<int>(x - len * CHAR_WIDTH / 2, 60, 255); + return (tmp + len * CHAR_WIDTH) <= 320; +} - strcpy(mb[conta_f], m1); +void DrasculaEngine::centerText(const char *message, int textX, int textY) { + char msg[200]; + char messageLine[200]; + char tmpMessageLine[200]; + *messageLine = 0; + *tmpMessageLine = 0; + char *curWord; + int curLine = 0; + int x = 0; + // original starts printing 4 lines above textY + int y = CLIP<int>(textY - (4 * CHAR_HEIGHT), 0, 320); - if (!strcmp(m2, "")) - break; + strcpy(msg, message); - scumm_strrev(m2); - m2[strlen(m2) - 1] = '\0'; - scumm_strrev(m2); - strcpy(m1, m2); - strcpy(m2, ""); - conta_f++; + // If the message fits on screen as-is, just print it here + if (textFitsCentered(msg, textX)) { + x = CLIP<int>(textX - strlen(msg) * CHAR_WIDTH / 2, 60, 255); + print_abc(msg, x, y); + return; } - fil = textY - (((conta_f + 3) * CHAR_HEIGHT)); + // Message doesn't fit on screen, split it + + // Get a word from the message + curWord = strtok(msg, " "); + while (curWord != NULL) { + // Check if the word and the current line fit on screen + if (strlen(tmpMessageLine) > 0) + strcat(tmpMessageLine, " "); + strcat(tmpMessageLine, curWord); + if (textFitsCentered(tmpMessageLine, textX)) { + // Line fits, so add the word to the current message line + strcpy(messageLine, tmpMessageLine); + } else { + // Line doesn't fit, so show the current line on screen and + // create a new one + // If it goes off screen, print_abc will adjust it + x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255); + print_abc(messageLine, x, y + curLine * CHAR_HEIGHT); + strcpy(messageLine, curWord); + strcpy(tmpMessageLine, curWord); + curLine++; + } + + // Get next word + curWord = strtok(NULL, " "); - for (h = 0; h < conta_f + 1; h++) { - textX3 = strlen(mb[h]) / 2; - print_abc(mb[h], ((textX) - textX3 * CHAR_WIDTH) - 1, fil); - fil = fil + CHAR_HEIGHT + 2; + if (curWord == NULL) { + x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255); + print_abc(messageLine, x, y + curLine * CHAR_HEIGHT); + } } } @@ -375,6 +352,8 @@ void DrasculaEngine::screenSaver() { int tempLine[320]; int tempRow[200]; + hideCursor(); + clearRoom(); loadPic("sv.alg", bgSurface, HALF_PAL); @@ -463,6 +442,7 @@ void DrasculaEngine::screenSaver() { free(ghost); loadPic(roomNumber, bgSurface, HALF_PAL); + showCursor(); } void DrasculaEngine::playFLI(const char *filefli, int vel) { @@ -621,12 +601,11 @@ void DrasculaEngine::decodeRLE(byte* srcPtr, byte* dstPtr) { pixel = *srcPtr++; } for (uint j = 0; j < repeat; j++) { - curByte++; - if (curByte > 64000) { + *dstPtr++ = pixel; + if (++curByte >= 64000) { stopProcessing = true; break; } - *dstPtr++ = pixel; } } } diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp index ef1d1cc7a3..32f07fce73 100644 --- a/engines/drascula/interface.cpp +++ b/engines/drascula/interface.cpp @@ -24,9 +24,34 @@ */ #include "drascula/drascula.h" +#include "graphics/cursorman.h" namespace Drascula { +void DrasculaEngine::setCursor(int cursor) { + switch (cursor) { + case kCursorCrosshair: + CursorMan.replaceCursor((const byte *)crosshairCursor, 40, 25, 20, 17); + break; + case kCursorCurrentItem: + CursorMan.replaceCursor((const byte *)mouseCursor, OBJWIDTH, OBJHEIGHT, 20, 17); + default: + break; + } +} + +void DrasculaEngine::showCursor() { + CursorMan.showMouse(true); +} + +void DrasculaEngine::hideCursor() { + CursorMan.showMouse(false); +} + +bool DrasculaEngine::isCursorVisible() { + return CursorMan.isVisible(); +} + void DrasculaEngine::selectVerbFromBar() { for (int n = 0; n < 7; n++) { if (mouseX > _verbBarX[n] && mouseX < _verbBarX[n + 1] && n > 0) { @@ -36,7 +61,7 @@ void DrasculaEngine::selectVerbFromBar() { } // no verb selected - withoutVerb(); + selectVerb(0); } void DrasculaEngine::selectVerb(int verb) { @@ -50,10 +75,17 @@ void DrasculaEngine::selectVerb(int verb) { addObject(pickedObject); } - copyBackground(OBJWIDTH * verb, c, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3); + for (int i = 0; i < OBJHEIGHT; i++) + memcpy(mouseCursor + i * OBJWIDTH, backSurface + OBJWIDTH * verb + (c + i) * 320, OBJWIDTH); + setCursor(kCursorCurrentItem); - takeObject = 1; - pickedObject = verb; + if (verb > 0) { + takeObject = 1; + pickedObject = verb; + } else { + takeObject = 0; + hasName = 0; + } } bool DrasculaEngine::confirmExit() { @@ -61,7 +93,7 @@ bool DrasculaEngine::confirmExit() { color_abc(kColorRed); updateRoom(); - centerText(_textsys[_lang][1], 160, 87); + centerText(_textsys[1], 160, 87); updateScreen(); delay(100); @@ -194,25 +226,4 @@ void DrasculaEngine::showMap() { } } -void DrasculaEngine::grr() { - int length = 30; - - color_abc(kColorDarkGreen); - - playFile("s10.als"); - - updateRoom(); - copyBackground(253, 110, 150, 65, 20, 30, drawSurface3, screenSurface); - - if (withVoices == 0) - centerText("groaaarrrrgghhhh!", 153, 65); - - updateScreen(); - - while (!isTalkFinished(&length)); - - updateRoom(); - updateScreen(); -} - } // End of namespace Drascula diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp index 01967d975d..c9c99aafa8 100644 --- a/engines/drascula/objects.cpp +++ b/engines/drascula/objects.cpp @@ -51,7 +51,9 @@ void DrasculaEngine::chooseObject(int object) { if (takeObject == 1 && menuScreen == 0) addObject(pickedObject); } - copyBackground(_x1d_menu[object], _y1d_menu[object], 0, 0, OBJWIDTH,OBJHEIGHT, backSurface, drawSurface3); + for (int i = 0; i < OBJHEIGHT; i++) + memcpy(mouseCursor + i * OBJWIDTH, backSurface + _x1d_menu[object] + (_y1d_menu[object] + i) * 320, OBJWIDTH); + setCursor(kCursorCurrentItem); takeObject = 1; pickedObject = object; } @@ -70,23 +72,10 @@ int DrasculaEngine::removeObject(int obj) { return result; } -void DrasculaEngine::withoutVerb() { - int c = (menuScreen == 1) ? 0 : 171; - - if (currentChapter == 5) { - if (takeObject == 1 && pickedObject != 16) - addObject(pickedObject); - } else { - if (takeObject == 1) - addObject(pickedObject); - } - copyBackground(0, c, 0, 0, OBJWIDTH,OBJHEIGHT, backSurface, drawSurface3); - - takeObject = 0; - hasName = 0; -} - void DrasculaEngine::gotoObject(int pointX, int pointY) { + bool cursorVisible = isCursorVisible(); + hideCursor(); + if (currentChapter == 5 || currentChapter == 6) { if (hare_se_ve == 0) { curX = roomX; @@ -113,6 +102,9 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) { } updateRoom(); updateScreen(); + + if (cursorVisible) + showCursor(); } void DrasculaEngine::checkObjects() { @@ -186,7 +178,7 @@ bool DrasculaEngine::pickupObject() { } updateEvents(); if (takeObject == 0) - withoutVerb(); + selectVerb(0); return false; } @@ -256,7 +248,7 @@ void DrasculaEngine::updateVisible() { if (roomNumber == 22 && flags[27] == 1) visible[3] = 0; if (roomNumber == 26 && flags[21] == 0) - strcpy(objName[2], _textmisc[_lang][0]); + strcpy(objName[2], _textmisc[0]); if (roomNumber == 26 && flags[18] == 1) visible[2] = 0; if (roomNumber == 26 && flags[12] == 1) diff --git a/engines/drascula/palette.cpp b/engines/drascula/palette.cpp index 6a93f21e55..ba174c9237 100644 --- a/engines/drascula/palette.cpp +++ b/engines/drascula/palette.cpp @@ -27,6 +27,17 @@ namespace Drascula { +const char colorTable[][3] = { + { 0, 0, 0 }, { 0x10, 0x3E, 0x28 }, + { 0, 0, 0 }, // unused + { 0x16, 0x3F, 0x16 }, { 0x09, 0x3F, 0x12 }, + { 0x3F, 0x3F, 0x15 }, + { 0, 0, 0 }, // unused + { 0x38, 0, 0 }, { 0x3F, 0x27, 0x0B }, + { 0x2A, 0, 0x2A }, { 0x30, 0x30, 0x30 }, + { 98, 91, 100 } +}; + void DrasculaEngine::setRGB(byte *pal, int colorCount) { int x, cnt = 0; @@ -70,17 +81,6 @@ void DrasculaEngine::setPalette(byte *PalBuf) { void DrasculaEngine::color_abc(int cl) { _color = cl; - char colorTable[][3] = { - { 0, 0, 0 }, { 0x10, 0x3E, 0x28 }, - { 0, 0, 0 }, // unused - { 0x16, 0x3F, 0x16 }, { 0x09, 0x3F, 0x12 }, - { 0x3F, 0x3F, 0x15 }, - { 0, 0, 0 }, // unused - { 0x38, 0, 0 }, { 0x3F, 0x27, 0x0B }, - { 0x2A, 0, 0x2A }, { 0x30, 0x30, 0x30 }, - { 98, 91, 100 } - }; - for (int i = 0; i <= 2; i++) gamePalette[254][i] = colorTable[cl][i]; @@ -127,64 +127,25 @@ void DrasculaEngine::fadeFromBlack(int fadeSpeed) { } } -void DrasculaEngine::assignDefaultPalette() { +void DrasculaEngine::assignPalette(DacPalette256 pal) { int color, component; for (color = 235; color < 253; color++) for (component = 0; component < 3; component++) - defaultPalette[color][component] = gamePalette[color][component]; -} - -void DrasculaEngine::assignBrightPalette() { - int color, component; - - for (color = 235; color < 253; color++) { - for (component = 0; component < 3; component++) - brightPalette[color][component] = gamePalette[color][component]; - } -} - -void DrasculaEngine::assignDarkPalette() { - int color, component; - - for (color = 235; color < 253; color++) { - for (component = 0; component < 3; component++) - darkPalette[color][component] = gamePalette[color][component]; - } + pal[color][component] = gamePalette[color][component]; } -void DrasculaEngine::setDefaultPalette() { +void DrasculaEngine::setDefaultPalette(DacPalette256 pal) { int color, component; for (color = 235; color < 253; color++) { for (component = 0; component < 3; component++) { - gamePalette[color][component] = defaultPalette[color][component]; + gamePalette[color][component] = pal[color][component]; } } setPalette((byte *)&gamePalette); } -void DrasculaEngine::setBrightPalette() { - int color, component; - - for (color = 235; color < 253; color++) { - for (component = 0; component < 3; component++) - gamePalette[color][component] = brightPalette[color][component]; - } - - setPalette((byte *)&gamePalette); -} - -void DrasculaEngine::setDarkPalette() { - int color, component; - - for (color = 235; color < 253; color++ ) - for (component = 0; component < 3; component++) - gamePalette[color][component] = darkPalette[color][component]; - - setPalette((byte *)&gamePalette); -} - void DrasculaEngine::setPaletteBase(int darkness) { signed char fade; unsigned int color, component; diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 37dddf4b7e..027685f56a 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -29,6 +29,24 @@ namespace Drascula { +struct doorInfo { + int chapter; + int doorNum; + int flag; +}; + +doorInfo doors[] = { + { 2, 138, 0 }, { 2, 136, 8 }, + { 2, 156, 16 }, { 2, 163, 17 }, + { 2, 177, 15 }, { 2, 175, 40 }, + { 2, 173, 36 }, { 4, 103, 0 }, + { 4, 104, 1 }, { 4, 105, 1 }, + { 4, 106, 2 }, { 4, 107, 2 }, + { 4, 110, 6 }, { 4, 114, 4 }, + { 4, 115, 4 }, { 4, 117, 5 }, + { 4, 120, 8 }, { 4, 122, 7 } +}; + typedef bool (DrasculaEngine::*RoomParser)(int args); struct DrasculaRoomParser { @@ -184,9 +202,9 @@ bool DrasculaEngine::room_3(int fl) { if (pickedObject == kVerbTalk && fl == 129) { talk(23); pause(6); - talk_sync(_text[_lang][50], "50.als", "11111111111144432554433"); + talk_sync(_text[50], "50.als", "11111111111144432554433"); } else if (pickedObject == kVerbTalk && fl == 133) { - talk_sync(_text[_lang][322], "322.als", "13333334125433333333"); + talk_sync(_text[322], "322.als", "13333334125433333333"); updateRoom(); updateScreen(); pause(25); @@ -248,11 +266,11 @@ bool DrasculaEngine::room_6(int fl) { talk(41); talk(42); } else if (pickedObject == kVerbOpen && fl == 138) - openDoor(0, 1); + toggleDoor(0, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 138) - closeDoor(0, 1); + toggleDoor(0, 1, kCloseDoor); else if (pickedObject == kVerbOpen && fl == 143 && flags[2] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface); updateScreen(); @@ -263,7 +281,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbClose && fl == 143 && flags[2] == 1) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); flags[2] = 0; updateRefresh_pre(); copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface); @@ -274,7 +292,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbOpen && fl == 139 && flags[1] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface); updateScreen(); @@ -287,7 +305,7 @@ bool DrasculaEngine::room_6(int fl) { updateScreen(); finishSound(); } else if (pickedObject == kVerbPick && fl == 140) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface); updateScreen(); @@ -350,9 +368,9 @@ bool DrasculaEngine::room_9(int fl) { bool DrasculaEngine::room_12(int fl) { if (pickedObject == kVerbOpen && fl == 156) - openDoor(16, 4); + toggleDoor(16, 4, kOpenDoor); else if (pickedObject == kVerbClose && fl == 156) - closeDoor(16, 4); + toggleDoor(16, 4, kCloseDoor); else hasAnswer = 0; @@ -365,11 +383,14 @@ bool DrasculaEngine::room_13(int fl) { trackProtagonist = 3; talk(412); strcpy(objName[1], "yoda"); - } else if (pickedObject == kVerbTalk && fl == 51) + } else if (pickedObject == kVerbTalk && fl == 51) { converse(7); - else if (pickedObject == 19 && fl == 51) - animation_1_3(); - else if (pickedObject == 9 && fl == 51) { + } else if (pickedObject == 19 && fl == 51) { + talk(413); + grr(); + pause(50); + talk(414); + } else if (pickedObject == 9 && fl == 51) { animation_2_3(); return true; } else @@ -404,10 +425,10 @@ bool DrasculaEngine::room_15(int fl) { talk(336); trackProtagonist = 3; talk(337); - talk_sync(_text[_lang][46], "46.als", "4442444244244"); + talk_sync(_text[46], "46.als", "4442444244244"); trackProtagonist = 1; } else if (pickedObject == 18 && fl == 188 && flags[26] == 0) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); copyRect(133, 135, curX + 6, curY, 39, 63, drawSurface3, screenSurface); updateScreen(); playSound(8); @@ -432,17 +453,17 @@ bool DrasculaEngine::room_15(int fl) { bool DrasculaEngine::room_16(int fl) { if (pickedObject == kVerbOpen && fl == 163) - openDoor(17, 0); + toggleDoor(17, 0, kOpenDoor); else if (pickedObject == kVerbClose && fl == 163) - closeDoor(17, 0); + toggleDoor(17, 0, kCloseDoor); else if (pickedObject == kVerbTalk && fl == 183) { talk(341); pause(10); - talk_sync(_text[_lang][50], "50.als", "11111111111144432554433"); + talk_sync(_text[50], "50.als", "11111111111144432554433"); pause(3); - talk_baul(83); + talk_trunk(83); } else if (pickedObject == kVerbOpen && fl == 183) { - openDoor(19, NO_DOOR); + toggleDoor(19, NO_DOOR, kOpenDoor); if (flags[20] == 0) { flags[20] = 1; trackProtagonist = 3; @@ -452,7 +473,7 @@ bool DrasculaEngine::room_16(int fl) { pickObject(22); } } else if (pickedObject == kVerbClose && fl == 183) - closeDoor(19, NO_DOOR); + toggleDoor(19, NO_DOOR, kCloseDoor); else if (pickedObject == kVerbLook && fl == 187) { talk(343); trackProtagonist = 3; @@ -470,16 +491,18 @@ bool DrasculaEngine::room_17(int fl) { talk(35); else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 0) talk(6); - else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 1) - animation_18_2(); - else if (pickedObject == kVerbOpen && fl == 177 && flags[18] == 1) + else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 1) { + talk(378); + talk_vonBraun(4, kVonBraunDoor); + converse(3); + } else if (pickedObject == kVerbOpen && fl == 177 && flags[18] == 1) talk(346); else if (pickedObject == kVerbOpen && fl == 177 && flags[14] == 0 && flags[18] == 0) - animation_22_2(); + playTalkSequence(22); // sequence 22, chapter 2 else if (pickedObject == kVerbOpen && fl == 177 && flags[14] == 1) - openDoor(15, 1); + toggleDoor(15, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 177 && flags[14] == 1) - closeDoor(15, 1); + toggleDoor(15, 1, kCloseDoor); else if (pickedObject == 11 && fl == 50 && flags[22] == 0) { talk(347); flags[29] = 1; @@ -497,7 +520,7 @@ bool DrasculaEngine::room_18(int fl) { else if (pickedObject == kVerbTalk && fl == 55 && flags[36] == 1) talk(109); else if (pickedObject == kVerbPick && fl == 182) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(44, 1, curX, curY, 41, 70, drawSurface2, screenSurface); updateRefresh(); @@ -519,7 +542,7 @@ bool DrasculaEngine::room_18(int fl) { trackProtagonist = 3; updateRoom(); updateScreen(); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyRect(1, 1, curX - 1, curY + 3, 42, 67, drawSurface2, screenSurface); updateRefresh(); @@ -539,19 +562,20 @@ bool DrasculaEngine::room_21(int fl) { if (pickedObject == kVerbOpen && fl == 101 && flags[28] == 0) talk(419); else if (pickedObject == kVerbOpen && fl == 101 && flags[28] == 1) - openDoor(0, 1); + toggleDoor(0, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 101) - closeDoor(0, 1); + toggleDoor(0, 1, kCloseDoor); else if(pickedObject == kVerbPick && fl == 141) { pickObject(19); visible[2] = 0; flags[10] = 1; } else if(pickedObject == 7 && fl == 101) { flags[28] = 1; - openDoor(0, 1); - withoutVerb(); + toggleDoor(0, 1, kOpenDoor); + selectVerb(0); } else if (pickedObject == 21 && fl == 179) { - animation_9_4(); + animate("st.bin", 14); + fadeToBlack(1); return true; } else hasAnswer = 0; @@ -570,7 +594,7 @@ bool DrasculaEngine::room_22(int fl) { playSound(1); hiccup(14); finishSound(); - withoutVerb(); + selectVerb(0); removeObject(22); updateVisible(); trackProtagonist = 3; @@ -590,15 +614,15 @@ bool DrasculaEngine::room_22(int fl) { bool DrasculaEngine::room_23(int fl) { if (pickedObject == kVerbOpen && fl == 103) { - openDoor(0, 0); + toggleDoor(0, 0, kOpenDoor); updateVisible(); } else if(pickedObject == kVerbClose && fl == 103) { - closeDoor(0, 0); + toggleDoor(0, 0, kCloseDoor); updateVisible(); } else if(pickedObject == kVerbOpen && fl == 104) - openDoor(1, 1); + toggleDoor(1, 1, kOpenDoor); else if(pickedObject == kVerbClose && fl == 104) - closeDoor(1, 1); + toggleDoor(1, 1, kCloseDoor); else if(pickedObject == kVerbPick && fl == 142) { pickObject(8); visible[2] = 0; @@ -615,13 +639,13 @@ bool DrasculaEngine::room_23(int fl) { bool DrasculaEngine::room_24(int fl) { if (pickedObject == kVerbOpen && fl == 105) - openDoor(1, 0); + toggleDoor(1, 0, kOpenDoor); else if (pickedObject == kVerbClose && fl == 105) - closeDoor(1, 0); + toggleDoor(1, 0, kCloseDoor); else if (pickedObject == kVerbOpen && fl == 106) - openDoor(2, 1); + toggleDoor(2, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 106) - closeDoor(2, 1); + toggleDoor(2, 1, kCloseDoor); else hasAnswer = 0; @@ -630,11 +654,11 @@ bool DrasculaEngine::room_24(int fl) { bool DrasculaEngine::room_26(int fl) { if (pickedObject == kVerbOpen && fl == 107 && flags[30] == 0) - openDoor(2, 0); + toggleDoor(2, 0, kOpenDoor); else if (pickedObject == kVerbOpen && fl == 107 && flags[30] == 1) talk(421); else if (pickedObject == kVerbClose && fl == 107) - closeDoor(2, 0); + toggleDoor(2, 0, kCloseDoor); else if (pickedObject == 10 && fl == 50 && flags[18] == 1 && flags[12] == 1) animation_5_4(); else if (pickedObject == 8 && fl == 50 && flags[18] == 1 && flags[12] == 1) @@ -648,7 +672,7 @@ bool DrasculaEngine::room_26(int fl) { pickObject(10); visible[1] = 0; flags[12] = 1; - closeDoor(2, 0); + toggleDoor(2, 0, kCloseDoor); trackProtagonist = 2; talk_igor(27, kIgorDoor); flags[30] = 1; @@ -671,17 +695,17 @@ bool DrasculaEngine::room_26(int fl) { bool DrasculaEngine::room_27(int fl) { if (pickedObject == kVerbOpen && fl == 110) - openDoor(6, 1); + toggleDoor(6, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 110) - closeDoor(6, 1); + toggleDoor(6, 1, kCloseDoor); else if (pickedObject == kVerbOpen && fl == 116 && flags[23] == 0) talk(419); else if (pickedObject == kVerbOpen && fl == 116 && flags[23] == 1) - openDoor(5, 3); + toggleDoor(5, 3, kOpenDoor); else if (pickedObject == 17 && fl == 116) { flags[23] = 1; - openDoor(5,3); - withoutVerb(); + toggleDoor(5, 3, kOpenDoor); + selectVerb(0); } else if (fl == 150) talk(460); else @@ -692,9 +716,9 @@ bool DrasculaEngine::room_27(int fl) { bool DrasculaEngine::room_29(int fl) { if (pickedObject == kVerbOpen && fl == 114) - openDoor(4, 1); + toggleDoor(4, 1, kOpenDoor); else if (pickedObject == kVerbClose && fl == 114) - closeDoor(4, 1); + toggleDoor(4, 1, kCloseDoor); else hasAnswer = 0; @@ -703,15 +727,15 @@ bool DrasculaEngine::room_29(int fl) { bool DrasculaEngine::room_30(int fl) { if (pickedObject == kVerbOpen && fl == 115) - openDoor(4, 0); + toggleDoor(4, 0, kOpenDoor); else if (pickedObject == kVerbClose && fl == 115) - closeDoor(4, 0); + toggleDoor(4, 0, kCloseDoor); else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 0) talk(422); else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 1 && flags[22] == 1) - openDoor(16, 1); + toggleDoor(16, 1, kOpenDoor); else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 1 && flags[22] == 0) { - openDoor(16, 1); + toggleDoor(16, 1, kOpenDoor); talk(423); flags[22] = 1; pickObject(12); @@ -720,7 +744,7 @@ bool DrasculaEngine::room_30(int fl) { if (flags[18] == 1) animation_6_4(); } else if (pickedObject == kVerbClose && fl == 144) - closeDoor(16, 1); + toggleDoor(16, 1, kCloseDoor); else if (pickedObject == 13 && fl == 144) { talk(424); flags[19] = 1; @@ -736,9 +760,9 @@ bool DrasculaEngine::room_31(int fl) { visible[1] = 0; flags[13] = 1; } else if (pickedObject == kVerbOpen && fl == 117) - openDoor(5, 0); + toggleDoor(5, 0, kOpenDoor); else if (pickedObject == kVerbClose && fl == 117) - closeDoor(5, 0); + toggleDoor(5, 0, kCloseDoor); else hasAnswer = 0; @@ -749,15 +773,15 @@ bool DrasculaEngine::room_34(int fl) { if (pickedObject == kVerbMove && fl == 146) animation_8_4(); else if (pickedObject == kVerbOpen && fl == 120 && flags[25] == 1) - openDoor(8, 2); + toggleDoor(8, 2, kOpenDoor); else if (pickedObject == kVerbOpen && fl == 120 && flags[25] == 0) { - openDoor(8, 2); + toggleDoor(8, 2, kOpenDoor); trackProtagonist = 3; talk(425); pickObject(14); flags[25] = 1; } else if (pickedObject == kVerbClose && fl == 120) - closeDoor(8, 2); + toggleDoor(8, 2, kCloseDoor); else hasAnswer=0; @@ -805,20 +829,27 @@ bool DrasculaEngine::room_53(int fl) { if (pickedObject == kVerbPick && fl == 120) { pickObject(16); visible[3] = 0; - } else if (pickedObject == kVerbMove && fl == 123) + } else if (pickedObject == kVerbMove && fl == 123) { animation_11_5(); - else if (pickedObject == 12 && fl == 52) - animation_10_5(); - else if (pickedObject == 15 && fl == 52) - animation_9_5(); - else if (pickedObject == 16 && fl == 121) { + } else if (pickedObject == 12 && fl == 52) { + flags[3] = 1; + talk(401); + selectVerb(0); + removeObject(12); + } else if (pickedObject == 15 && fl == 52) { + flags[4] = 1; + talk(401); + selectVerb(0); + removeObject(15); + } else if (pickedObject == 16 && fl == 121) { flags[2] = 1; - withoutVerb(); + selectVerb(0); updateVisible(); + pickedObject = kVerbMove; } else if (pickedObject == 16) { - talk(439); - withoutVerb(); + // Wall plug in chapter 5 visible[3] = 1; + hasAnswer = 0; } else hasAnswer = 0; @@ -851,7 +882,7 @@ bool DrasculaEngine::room_54(int fl) { } else if (pickedObject == 10 && fl == 119) { pause(4); talk(436); - withoutVerb(); + selectVerb(0); removeObject(10); } else hasAnswer = 0; @@ -886,10 +917,12 @@ bool DrasculaEngine::room_56(int fl) { } bool DrasculaEngine::room_58(int fl) { - if (pickedObject == kVerbMove && fl == 103) - animation_7_6(); - else + if (pickedObject == kVerbMove && fl == 103) { + flags[8] = 1; + updateVisible(); + } else { hasAnswer = 0; + } return true; } @@ -933,19 +966,19 @@ bool DrasculaEngine::room_59(int fl) { talk_htel(240); color_abc(kColorBrown); - talk_solo(_textvb[_lang][58], "VB58.als"); + talk_solo(_textvb[58], "VB58.als"); talk_htel(241); color_abc(kColorBrown); - talk_solo(_textvb[_lang][59], "VB59.als"); + talk_solo(_textvb[59], "VB59.als"); talk_htel(242); color_abc(kColorBrown); - talk_solo(_textvb[_lang][60], "VB60.als"); + talk_solo(_textvb[60], "VB60.als"); talk_htel(196); color_abc(kColorBrown); - talk_solo(_textvb[_lang][61],"VB61.als"); + talk_solo(_textvb[61],"VB61.als"); talk_htel(244); color_abc(kColorBrown); - talk_solo(_textvb[_lang][62], "VB62.als"); + talk_solo(_textvb[62], "VB62.als"); clearRoom(); loadPic("aux59.alg", drawSurface3); loadPic(96, frontSurface, COMPLETE_PAL); @@ -953,7 +986,7 @@ bool DrasculaEngine::room_59(int fl) { loadPic(59, bgSurface, HALF_PAL); trackProtagonist = 3; talk(245); - withoutVerb(); + selectVerb(0); flags[11] = 1; } } else @@ -963,17 +996,27 @@ bool DrasculaEngine::room_59(int fl) { } bool DrasculaEngine::room_60(int fl) { - if (pickedObject == kVerbMove && fl == 112) - animation_10_6(); - else if (pickedObject == kVerbTalk && fl == 52) { + if (pickedObject == kVerbMove && fl == 112) { + playSound(14); + copyBackground(); + updateRefresh_pre(); + copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface); + updateScreen(); + finishSound(); + talk_bartender(23, 1); + flags[7] = 1; + } else if (pickedObject == kVerbTalk && fl == 52) { talk(266); talk_bartender(1, 1); converse(12); - withoutVerb(); + selectVerb(0); pickedObject = 0; - } else if (pickedObject == 21 && fl == 56) - animation_18_6(); - else if (pickedObject == 9 && fl == 56 && flags[6] == 1) { + } else if (pickedObject == 21 && fl == 56) { + flags[6] = 1; + selectVerb(0); + removeObject(21); + animate("beb.bin", 10); + } else if (pickedObject == 9 && fl == 56 && flags[6] == 1) { animation_9_6(); return true; } else if (pickedObject == 9 && fl == 56 && flags[6] == 0) { @@ -1089,11 +1132,9 @@ void DrasculaEngine::updateRefresh_pre() { void DrasculaEngine::update_1_pre() { if (curX > 98 && curX < 153) { - changeColor = 1; - setDarkPalette(); + setDefaultPalette(darkPalette); } else { - changeColor = 0; - setBrightPalette(); + setDefaultPalette(brightPalette); } if (flags[8] == 0) @@ -1101,8 +1142,8 @@ void DrasculaEngine::update_1_pre() { } void DrasculaEngine::update_2() { - int batPos[6]; int difference; + int w, h; int batX[] = {0, 38, 76, 114, 152, 190, 228, 266, 0, 38, 76, 114, 152, 190, 228, 266, 0, 38, 76, 114, 152, 190, @@ -1122,24 +1163,19 @@ void DrasculaEngine::update_2() { if (actorFrames[kFrameBat] == 41) actorFrames[kFrameBat] = 0; - batPos[0] = batX[actorFrames[kFrameBat]]; - batPos[1] = batY[actorFrames[kFrameBat]]; - if (actorFrames[kFrameBat] < 22) { - batPos[4] = 37; - batPos[5] = 21; + w = 37; + h = 21; } else if (actorFrames[kFrameBat] > 27) { - batPos[4] = 57; - batPos[5] = 36; + w = 57; + h = 36; } else { - batPos[4] = 47; - batPos[5] = 22; + w = 47; + h = 22; } - batPos[2] = 239; - batPos[3] = 19; - - copyRectClip(batPos, drawSurface3, screenSurface); + copyRect(batX[actorFrames[kFrameBat]], batY[actorFrames[kFrameBat]], + 239, 19, w, h, drawSurface3, screenSurface); difference = getTime() - savedTime; if (difference >= 6) { actorFrames[kFrameBat]++; @@ -1158,22 +1194,18 @@ void DrasculaEngine::update_3() { void DrasculaEngine::update_4() { if (curX > 190) { - changeColor = 1; - setDarkPalette(); + setDefaultPalette(darkPalette); } else { - changeColor = 0; - setBrightPalette(); + setDefaultPalette(brightPalette); } } void DrasculaEngine::update_6_pre() { if ((curX > 149 && curY + curHeight > 160 && curX < 220 && curY + curHeight < 188) || (curX > 75 && curY + curHeight > 183 && curX < 145)) { - changeColor = 0; - setBrightPalette(); + setDefaultPalette(brightPalette); } else { - changeColor = 1; - setDarkPalette(); + setDefaultPalette(darkPalette); } } @@ -1463,6 +1495,7 @@ void DrasculaEngine::update_102() { } bool DrasculaEngine::checkAction(int fl) { + hideCursor(); characterMoved = 0; updateRoom(); updateScreen(); @@ -1481,7 +1514,7 @@ bool DrasculaEngine::checkAction(int fl) { || (pickedObject == kVerbOpen && fl == 22 && flags[23] == 0)) { talk(164); flags[23] = 1; - withoutVerb(); + selectVerb(0); addObject(kItemMoney); addObject(kItemTwoCoins); } else if (pickedObject == kVerbLook && fl == 22 && flags[23] == 1) @@ -1492,7 +1525,7 @@ bool DrasculaEngine::checkAction(int fl) { hasAnswer = 0; } else if (currentChapter == 4) { if ((pickedObject == 18 && fl == 19) || (pickedObject == 19 && fl == 18)) { - withoutVerb(); + selectVerb(0); chooseObject(21); removeObject(18); removeObject(19); @@ -1504,13 +1537,7 @@ bool DrasculaEngine::checkAction(int fl) { talk(495); } else hasAnswer = 0; - } else if (currentChapter == 5) { - if (pickedObject == kVerbLook && fl == 9) { - talk(482); - talk(483); - } else - hasAnswer = 0; - } else if (currentChapter == 6) { + } else if (currentChapter == 5 || currentChapter == 6) { if (pickedObject == kVerbLook && fl == 9) { talk(482); talk(483); @@ -1528,8 +1555,10 @@ bool DrasculaEngine::checkAction(int fl) { hasAnswer = 0; } else if (currentChapter == 3) { if (roomNumber == 13) { - if (room(13, fl)) + if (room(13, fl)) { + showCursor(); return true; + } } else hasAnswer = 0; } else if (currentChapter == 4) { @@ -1540,14 +1569,18 @@ bool DrasculaEngine::checkAction(int fl) { else if (pickedObject == 12 && fl == 50 && flags[18] == 0) talk(487); else if (roomNumber == 21) { - if (room(21, fl)) + if (room(21, fl)) { + showCursor(); return true; + } } else hasAnswer = 0; } else if (currentChapter == 5) { if (roomNumber == 56) { - if (room(56, fl)) + if (room(56, fl)) { + showCursor(); return true; + } } else hasAnswer = 0; } else if (currentChapter == 6) { @@ -1558,8 +1591,10 @@ bool DrasculaEngine::checkAction(int fl) { else if (roomNumber == 102) room(102, fl); else if (roomNumber == 60) { - if (room(60, fl)) + if (room(60, fl)) { + showCursor(); return true; + } } else hasAnswer = 0; @@ -1575,6 +1610,7 @@ bool DrasculaEngine::checkAction(int fl) { if (hasAnswer == 0 && (hasName == 1 || menuScreen == 1)) room(0, -1); + showCursor(); return false; } @@ -1600,6 +1636,7 @@ bool DrasculaEngine::room(int rN, int fl) { void DrasculaEngine::enterRoom(int roomIndex) { debug(2, "Entering room %d", roomIndex); + showCursor(); char fileName[20]; sprintf(fileName, "%d.ald", roomIndex); @@ -1661,7 +1698,7 @@ void DrasculaEngine::enterRoom(int roomIndex) { getIntFromLine(buffer, size, &_destX[l]); getIntFromLine(buffer, size, &_destY[l]); getIntFromLine(buffer, size, &trackCharacter_alkeva[l]); - getIntFromLine(buffer, size, &alapuertakeva[l]); + getIntFromLine(buffer, size, &roomExits[l]); updateDoor(l); } } @@ -1716,16 +1753,15 @@ void DrasculaEngine::enterRoom(int roomIndex) { copyBackground(0, 171, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3); - setDefaultPalette(); + setDefaultPalette(defaultPalette); if (palLevel != 0) setPaletteBase(palLevel); - assignBrightPalette(); - setDefaultPalette(); + assignPalette(brightPalette); + setDefaultPalette(defaultPalette); setPaletteBase(palLevel + 2); - assignDarkPalette(); + assignPalette(darkPalette); - setBrightPalette(); - changeColor = -1; + setDefaultPalette(brightPalette); if (currentChapter == 2) color_abc(kColorLightGreen); @@ -1821,8 +1857,9 @@ void DrasculaEngine::enterRoom(int roomIndex) { if (currentChapter == 5) { if (roomNumber == 45) hare_se_ve = 0; - if (roomNumber == 49 && flags[7] == 0) - animation_4_5(); + if (roomNumber == 49 && flags[7] == 0) { + playTalkSequence(4); // sequence 4, chapter 5 + } } updateRoom(); @@ -1830,7 +1867,7 @@ void DrasculaEngine::enterRoom(int roomIndex) { void DrasculaEngine::clearRoom() { memset(VGA, 0, 64000); - _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200); + _system->clearScreen(); _system->updateScreen(); } @@ -1839,49 +1876,50 @@ bool DrasculaEngine::exitRoom(int l) { int roomNum = 0; - if (currentChapter == 1) { - if (objectNum[l] == 105 && flags[0] == 0) - talk(442); - else { - updateDoor(l); - if (isDoor[l] != 0) { - gotoObject(roomObjX[l], roomObjY[l]); - trackProtagonist = trackObj[l]; - updateRoom(); - updateScreen(); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; - - if (objectNum[l] == 105) { - animation_2_1(); - return true; - } - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX = -1; - enterRoom(roomNum); - } + // Player can't exit the inn in chapter 1 + if (currentChapter == 1 && objectNum[l] == 104) { + return false; + } + + if (currentChapter == 1 && objectNum[l] == 105 && flags[0] == 0) { + talk(442); + return false; + } + + updateDoor(l); + if (isDoor[l] != 0 && + ((currentChapter != 3 && currentChapter != 5) || visible[l] == 1)) { + + hideCursor(); + gotoObject(roomObjX[l], roomObjY[l]); + if (currentChapter != 2) { + trackProtagonist = trackObj[l]; + updateRoom(); + updateScreen(); } - } else if (currentChapter == 2) { - updateDoor(l); - if (isDoor[l] != 0) { - gotoObject(roomObjX[l], roomObjY[l]); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; + characterMoved = 0; + trackProtagonist = trackCharacter_alkeva[l]; + objExit = roomExits[l]; + doBreak = 1; + previousMusic = roomMusic; + + // Object specific actions + if (currentChapter == 1 && objectNum[l] == 105) { + animation_2_1(); + return true; + } else if (currentChapter == 2) { if (objectNum[l] == 136) animation_2_2(); - if (objectNum[l] == 124) - animation_3_2(); + if (objectNum[l] == 124) { + gotoObject(163, 106); + gotoObject(287, 101); + trackProtagonist = 0; + } if (objectNum[l] == 173) { animation_35_2(); return true; - } if (objectNum[l] == 146 && flags[39] == 1) { + } + if (objectNum[l] == 146 && flags[39] == 1) { flags[5] = 1; flags[11] = 1; } @@ -1890,93 +1928,27 @@ bool DrasculaEngine::exitRoom(int l) { removeObject(kItemEarWithEarPlug); addObject(kItemEarplugs); } - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX =- 1; - enterRoom(roomNum); - } - } else if (currentChapter == 3) { - updateDoor(l); - if (isDoor[l] != 0 && visible[l] == 1) { - gotoObject(roomObjX[l], roomObjY[l]); - trackProtagonist = trackObj[l]; - updateRoom(); - updateScreen(); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX =- 1; - enterRoom(roomNum); - } - } else if (currentChapter == 4) { - updateDoor(l); - if (isDoor[l] != 0) { - gotoObject(roomObjX[l], roomObjY[l]); - trackProtagonist = trackObj[l]; - updateRoom(); - updateScreen(); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; - - if (objectNum[l] == 108) - gotoObject(171, 78); - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX = -1; - enterRoom(roomNum); + } else if (currentChapter == 4 && objectNum[l] == 108) { + gotoObject(171, 78); } - } else if (currentChapter == 5) { - updateDoor(l); - if (isDoor[l] != 0 && visible[l] == 1) { - gotoObject(roomObjX[l], roomObjY[l]); - trackProtagonist = trackObj[l]; - updateRoom(); - updateScreen(); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; + + if (currentChapter == 5) hare_se_ve = 1; - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX = -1; - enterRoom(roomNum); - } - } else if (currentChapter == 6) { - updateDoor(l); - if (isDoor[l] != 0) { - gotoObject(roomObjX[l], roomObjY[l]); - trackProtagonist = trackObj[l]; - updateRoom(); - updateScreen(); - characterMoved = 0; - trackProtagonist = trackCharacter_alkeva[l]; - objExit = alapuertakeva[l]; - doBreak = 1; - previousMusic = roomMusic; - clearRoom(); - sscanf(_targetSurface[l], "%d", &roomNum); - curX = -1; - enterRoom(roomNum); - if (objExit == 105) - animation_19_6(); - } + clearRoom(); + sscanf(_targetSurface[l], "%d", &roomNum); + curX = -1; + enterRoom(roomNum); + + if (currentChapter == 6 && objExit == 105) + animation_19_6(); } return false; } void DrasculaEngine::updateRoom() { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 3) { if (flags[0] == 0) @@ -1990,67 +1962,41 @@ void DrasculaEngine::updateRoom() { } void DrasculaEngine::updateDoor(int doorNum) { - if (currentChapter == 1 || currentChapter == 3 || currentChapter == 5 || currentChapter == 6) + if (currentChapter != 2 && currentChapter != 4) return; - else if (currentChapter == 2) { - if (objectNum[doorNum] == 138) - isDoor[doorNum] = flags[0]; - else if (objectNum[doorNum] == 136) - isDoor[doorNum] = flags[8]; - else if (objectNum[doorNum] == 156) - isDoor[doorNum] = flags[16]; - else if (objectNum[doorNum] == 163) - isDoor[doorNum] = flags[17]; - else if (objectNum[doorNum] == 177) - isDoor[doorNum] = flags[15]; - else if (objectNum[doorNum] == 175) - isDoor[doorNum] = flags[40]; - else if (objectNum[doorNum] == 173) - isDoor[doorNum] = flags[36]; - } else if (currentChapter == 4) { + + for (int i = 0; i < ARRAYSIZE(doors); i++) { + if (doors[i].chapter == currentChapter && + objectNum[doorNum] == doors[i].doorNum) { + isDoor[doorNum] = flags[doors[i].flag]; + return; + } + } + + if (currentChapter == 4) { if (objectNum[doorNum] == 101 && flags[0] == 0) isDoor[doorNum] = 0; else if (objectNum[doorNum] == 101 && flags[0] == 1 && flags[28] == 1) isDoor[doorNum] = 1; - else if (objectNum[doorNum] == 103) - isDoor[doorNum] = flags[0]; - else if (objectNum[doorNum] == 104) - isDoor[doorNum] = flags[1]; - else if (objectNum[doorNum] == 105) - isDoor[doorNum] = flags[1]; - else if (objectNum[doorNum] == 106) - isDoor[doorNum] = flags[2]; - else if (objectNum[doorNum] == 107) - isDoor[doorNum] = flags[2]; - else if (objectNum[doorNum] == 110) - isDoor[doorNum] = flags[6]; - else if (objectNum[doorNum] == 114) - isDoor[doorNum] = flags[4]; - else if (objectNum[doorNum] == 115) - isDoor[doorNum] = flags[4]; else if (objectNum[doorNum] == 116 && flags[5] == 0) isDoor[doorNum] = 0; else if (objectNum[doorNum] == 116 && flags[5] == 1 && flags[23] == 1) isDoor[doorNum] = 1; - else if (objectNum[doorNum] == 117) - isDoor[doorNum] = flags[5]; - else if (objectNum[doorNum] == 120) - isDoor[doorNum] = flags[8]; - else if (objectNum[doorNum] == 122) - isDoor[doorNum] = flags[7]; } } -void DrasculaEngine::openDoor(int nflag, int doorNum) { - if (flags[nflag] == 0) { - if (currentChapter == 1 /*|| currentChapter == 4*/) { - if (nflag != 7) { - playSound(3); - flags[nflag] = 1; - } - } else { +void DrasculaEngine::toggleDoor(int nflag, int doorNum, int action) { + if ((flags[nflag] == 0 && action == kOpenDoor) || + (flags[nflag] == 1 && action == kCloseDoor)) { + if (currentChapter == 1 && nflag == 7 && action == kOpenDoor) + return; + + if (action == kOpenDoor) { playSound(3); flags[nflag] = 1; + } else { + playSound(4); + flags[nflag] = 0; } if (doorNum != NO_DOOR) @@ -2058,20 +2004,7 @@ void DrasculaEngine::openDoor(int nflag, int doorNum) { updateRoom(); updateScreen(); finishSound(); - withoutVerb(); - } -} - -void DrasculaEngine::closeDoor(int nflag, int doorNum) { - if (flags[nflag] == 1) { - playSound(4); - flags[nflag] = 0; - if (doorNum != NO_DOOR) - updateDoor(doorNum); - updateRoom(); - updateScreen(); - finishSound(); - withoutVerb(); + selectVerb(0); } } diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp index 6f88a58fbb..503d2ab639 100644 --- a/engines/drascula/saveload.cpp +++ b/engines/drascula/saveload.cpp @@ -50,7 +50,7 @@ bool DrasculaEngine::saveLoadScreen() { } } for (n = 0; n < NUM_SAVES; n++) - sav->readLine(names[n], 23); + sav->readLine_OLD(names[n], 23); delete sav; loadPic("savescr.alg", bgSurface, HALF_PAL); @@ -60,16 +60,16 @@ bool DrasculaEngine::saveLoadScreen() { select[0] = 0; _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); + setCursor(kCursorCrosshair); for (;;) { y = 27; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); for (n = 0; n < NUM_SAVES; n++) { print_abc(names[n], 116, y); y = y + 9; } print_abc(select, 117, 15); - setCursorTable(); updateScreen(); y = 27; @@ -172,6 +172,8 @@ bool DrasculaEngine::saveLoadScreen() { delay(5); } + selectVerb(0); + clearRoom(); loadPic(roomNumber, bgSurface, HALF_PAL); selectionMade = 0; @@ -198,7 +200,7 @@ bool DrasculaEngine::loadGame(const char *gameName) { if (savedChapter != currentChapter) { strcpy(saveName, gameName); currentChapter = savedChapter - 1; - hay_que_load = 1; + loadedDifferentChapter = 1; return false; } sav->read(currentData, 20); @@ -216,10 +218,10 @@ bool DrasculaEngine::loadGame(const char *gameName) { takeObject = sav->readSint32LE(); pickedObject = sav->readSint32LE(); - hay_que_load = 0; + loadedDifferentChapter = 0; sscanf(currentData, "%d.ald", &roomNum); enterRoom(roomNum); - withoutVerb(); + selectVerb(0); return true; } @@ -253,9 +255,6 @@ void DrasculaEngine::saveGame(char gameName[]) { warning("Can't write file '%s'. (Disk full?)", gameName); delete out; - - playSound(99); - finishSound(); } } // End of namespace Drascula diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp index 2eb40e2e30..6a3d83cae6 100644 --- a/engines/drascula/sound.cpp +++ b/engines/drascula/sound.cpp @@ -23,6 +23,10 @@ * */ +#include "sound/mixer.h" +#include "sound/voc.h" +#include "sound/audiocd.h" + #include "drascula/drascula.h" namespace Drascula { @@ -37,9 +41,15 @@ void DrasculaEngine::updateVolume(Audio::Mixer::SoundType soundType, int prevVol } void DrasculaEngine::volumeControls() { + if (_lang == kSpanish) + loadPic(95, tableSurface); + copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface); updateScreen(73, 63, 73, 63, 177, 97, screenSurface); + setCursor(kCursorCrosshair); + showCursor(); + for (;;) { int masterVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16), 0, 15); int voiceVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 16), 0, 15); @@ -57,8 +67,6 @@ void DrasculaEngine::volumeControls() { copyBackground(183, 56, 138, voiceVolumeY, 39, 2 + voiceVolume * 4, tableSurface, screenSurface); copyBackground(183, 56, 194, musicVolumeY, 39, 2 + musicVolume * 4, tableSurface, screenSurface); - setCursorTable(); - updateScreen(); updateEvents(); @@ -84,6 +92,11 @@ void DrasculaEngine::volumeControls() { } + if (_lang == kSpanish) + loadPic(974, tableSurface); + + selectVerb(0); + updateEvents(); } @@ -110,6 +123,10 @@ void DrasculaEngine::stopMusic() { AudioCD.stop(); } +void DrasculaEngine::updateMusic() { + AudioCD.updateCD(); +} + int DrasculaEngine::musicStatus() { return AudioCD.isPlaying(); } @@ -141,7 +158,18 @@ void DrasculaEngine::playFile(const char *fname) { if (_arj.open(fname)) { int soundSize = _arj.size(); byte *soundData = (byte *)malloc(soundSize); - _arj.seek(32); + + if (!(!strcmp(fname, "3.als") && soundSize == 145166 && _lang != kSpanish)) { + _arj.seek(32); + } else { + // WORKAROUND: File 3.als with English speech files has a big silence at + // its beginning and end. We seek past the silence at the beginning, + // and ignore the silence at the end + // Fixes bug #2111815 - "DRASCULA: Voice delayed" + _arj.seek(73959, SEEK_SET); + soundSize = 117158 - 73959; + } + _arj.read(soundData, soundSize); _arj.close(); diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index a89c5ff734..7bf55b7c40 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -36,9 +36,8 @@ void DrasculaEngine::talkInit(const char *filename) { playFile(filename); } -bool DrasculaEngine::isTalkFinished(int* length) { - byte key = getScan(); - if (key != 0) +bool DrasculaEngine::isTalkFinished() { + if (getScan() != 0) stopSound(); if (soundIsActive()) return false; @@ -55,13 +54,12 @@ bool DrasculaEngine::isTalkFinished(int* length) { void DrasculaEngine::talk_igor(int index, int talkerType) { char filename[20]; sprintf(filename, "I%i.als", index); - const char *said = _texti[_lang][index]; + const char *said = _texti[index]; int x_talk0[8] = { 56, 82, 108, 134, 160, 186, 212, 238 }; int x_talk1[8] = { 56, 86, 116, 146, 176, 206, 236, 266 }; int x_talk3[4] = { 80, 102, 124, 146 }; int x_talk4[4] = { 119, 158, 197, 236 }; int face = 0; - int length = strlen(said); color_abc(kColorWhite); @@ -70,11 +68,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { do { if (talkerType == kIgorDch || talkerType == kIgorFront) { face = _rnd->getRandomNumber(7); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); } else if (talkerType == kIgorSeated || talkerType == kIgorWig) { face = _rnd->getRandomNumber(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); } @@ -119,7 +117,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { updateScreen(); pause(3); } - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); if ((talkerType == kIgorFront && currentChapter == 6) || talkerType == kIgorDoor || talkerType == kIgorSeated || talkerType == kIgorWig) { @@ -127,7 +125,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { } if (talkerType == kIgorDch || (talkerType == kIgorFront && currentChapter == 1)) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); placeIgor(); placeDrascula(); } @@ -136,12 +134,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) { // Talker type 0: talk_dr_izq, 1: talk_dr_dch void DrasculaEngine::talk_drascula(int index, int talkerType) { - const char *said = _textd[_lang][index]; + const char *said = _textd[index]; char filename[20]; sprintf(filename, "d%i.als", index); int x_talk[8] = { 1, 40, 79, 118, 157, 196, 235, 274 }; int face; - int length = strlen(said); int offset = (talkerType == 0) ? 0 : 7; int offset2 = (talkerType == 0) ? 90 : 58; @@ -152,7 +149,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { do { face = _rnd->getRandomNumber(7); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -176,10 +173,10 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); if (talkerType == 0) - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); if (talkerType == 1 && currentChapter == 6) updateRoom(); @@ -193,8 +190,41 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) { updateScreen(); } +void DrasculaEngine::talk_drascula_big(int index) { + char filename[20]; + sprintf(filename, "d%i.als", index); + const char *said = _textd[index]; + int x_talk[4] = {47, 93, 139, 185}; + int face; + int l = 0; + + color_abc(kColorRed); + + talkInit(filename); + + do { + face = _rnd->getRandomNumber(3); + copyBackground(); + copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); + copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); + l++; + if (l == 7) + l = 0; + + if (withVoices == 0) + centerText(said, 191, 69); + + updateScreen(); + + pause(3); + + byte key = getScan(); + if (key == Common::KEYCODE_ESCAPE) + term_int = 1; + } while (!isTalkFinished()); +} + void DrasculaEngine::talk_solo(const char *said, const char *filename) { - int length = strlen(said); if (currentChapter == 1) color_abc(color_solo); @@ -204,7 +234,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) { talkInit(filename); if (currentChapter == 6) - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); do { if (withVoices == 0) { @@ -216,10 +246,10 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) { centerText(said, 173, 92); } updateScreen(); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); if (currentChapter == 6) { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } } @@ -231,15 +261,14 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) { // Line 82 is a special case if (index != 82) - said = _textt[_lang][index]; + said = _textt[index]; else { sprintf(filename, "d%i.als", index); - said = _textd[_lang][index]; + said = _textd[index]; } int x_talk[9] = { 1, 23, 45, 67, 89, 111, 133, 155, 177 }; int face; - int length = strlen(said); color_abc(kColorMaroon); @@ -260,7 +289,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) { face = _rnd->getRandomNumber(5); } - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -277,7 +306,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) { updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); updateRoom(); updateScreen(); @@ -286,10 +315,9 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) { void DrasculaEngine::talk_bj(int index) { char filename[20]; sprintf(filename, "BJ%i.als", index); - const char *said = _textbj[_lang][index]; + const char *said = _textbj[index]; int x_talk[5] = { 64, 92, 120, 148, 176 }; int face; - int length = strlen(said); color_abc(kColorWhite); @@ -299,7 +327,7 @@ void DrasculaEngine::talk_bj(int index) { if (currentChapter != 5) { face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -325,7 +353,7 @@ void DrasculaEngine::talk_bj(int index) { updateScreen(); } - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); updateRoom(); updateScreen(); @@ -334,7 +362,7 @@ void DrasculaEngine::talk_bj(int index) { void DrasculaEngine::talk(int index) { char name[20]; sprintf(name, "%i.als", index); - talk(_text[_lang][index], name); + talk(_text[index], name); } void DrasculaEngine::talk(const char *said, const char *filename) { @@ -344,7 +372,6 @@ void DrasculaEngine::talk(const char *said, const char *filename) { int y_mask_talk = 170; int face; - int length = strlen(said); if (currentChapter == 6) { if (flags[0] == 0 && roomNumber == 102) { @@ -375,7 +402,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) { do { face = _rnd->getRandomNumber(5); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 2) @@ -442,7 +469,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) { updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); updateRoom(); updateScreen(); @@ -456,7 +483,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) { void DrasculaEngine::talk_pianist(int index) { char filename[20]; sprintf(filename, "P%i.als", index); - const char* said = _textp[_lang][index]; + const char* said = _textp[index]; int x_talk[4] = { 97, 145, 193, 241 }; int coords[7] = { 139, 228, 112, 47, 60, 221, 128 }; @@ -467,7 +494,7 @@ void DrasculaEngine::talk_pianist(int index) { void DrasculaEngine::talk_drunk(int index) { char filename[20]; sprintf(filename, "B%i.als", index); - const char *said = _textb[_lang][index]; + const char *said = _textb[index]; int x_talk[8] = { 1, 21, 41, 61, 81, 101, 121, 141 }; int coords[7] = { 29, 177, 50, 19, 19, 181, 54 }; @@ -498,13 +525,15 @@ void DrasculaEngine::talk_drunk(int index) { } } -void DrasculaEngine::talk_vonBraun(int index) { +// talker types: +// 0: kVonBraunNormal +// 1: KVonBraunDoor +void DrasculaEngine::talk_vonBraun(int index, int talkerType) { char filename[20]; sprintf(filename, "VB%i.als", index); - const char *said = _textvb[_lang][index]; + const char *said = _textvb[index]; int x_talk[6] = {1, 27, 53, 79, 105, 131}; int face; - int length = strlen(said); color_abc(kColorBrown); @@ -513,50 +542,33 @@ void DrasculaEngine::talk_vonBraun(int index) { copyBackground(vonBraunX + 5, 64, OBJWIDTH + 1, 0, 25, 27, bgSurface, drawSurface3); do { - if (trackVonBraun == 1) { - face = _rnd->getRandomNumber(5); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - - moveCharacters(); - moveVonBraun(); + if (talkerType == kVonBraunNormal) { + if (trackVonBraun == 1) { + face = _rnd->getRandomNumber(5); + copyBackground(); - copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); - copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); - updateRefresh(); - } + moveCharacters(); + moveVonBraun(); - if (withVoices == 0) - centerText(said, vonBraunX, 66); - - updateScreen(); - - pause(3); - } while (!isTalkFinished(&length)); - - updateRoom(); - updateScreen(); - if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0) - playMusic(roomMusic); -} - -void DrasculaEngine::talk_vonBraunpuerta(int index) { - char filename[20]; - sprintf(filename, "VB%i.als", index); - const char *said = _textvb[_lang][index]; - int length = strlen(said); - - color_abc(kColorBrown); + copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface); + copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface); + updateRefresh(); + } - talkInit(filename); + if (withVoices == 0) + centerText(said, vonBraunX, 66); - do { - updateRoom(); + updateScreen(); + pause(3); + } else { + updateRoom(); - if (withVoices == 0) - centerText(said, 150, 80); + if (withVoices == 0) + centerText(said, 150, 80); - updateScreen(); - } while (!isTalkFinished(&length)); + updateScreen(); + } + } while (!isTalkFinished()); updateRoom(); updateScreen(); @@ -570,60 +582,56 @@ void DrasculaEngine::talk_blind(int index) { // voice files start from 58, not 1 char filename[20]; sprintf(filename, "d%i.als", index + TEXTD_START - 1); - const char *said = _textd[_lang][index + TEXTD_START - 1]; - const char *syncChar = _textd1[_lang][index - 1]; + const char *said = _textd[index + TEXTD_START - 1]; + const char *syncChar = _textd1[index - 1]; - byte *faceBuffer; int p = 0; - int pos_blind[6] = { 0, 2, 73, 1, 126, 149 }; - int length = strlen(said); + int bX = 0; + int h = 149; color_abc(kColorBrown); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); talkInit(filename); do { - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - pos_blind[5] = 149; + copyBackground(); + h = 149; char c = toupper(syncChar[p]); if (c == '0' || c == '2' || c == '4' || c == '6') - pos_blind[0] = 1; + bX = 1; else - pos_blind[0] = 132; + bX = 132; if (c == '0' || c == '1') - faceBuffer = drawSurface3; + copyRect(bX, 2, 73, 1, 126, h, drawSurface3, screenSurface); else if (c == '2' || c == '3') - faceBuffer = extraSurface; + copyRect(bX, 2, 73, 1, 126, h, extraSurface, screenSurface); else if (c == '4' || c == '5') - faceBuffer = backSurface; + copyRect(bX, 2, 73, 1, 126, h, backSurface, screenSurface); else { - faceBuffer = frontSurface; - pos_blind[5] = 146; + h = 146; + copyRect(bX, 2, 73, 1, 126, h, frontSurface, screenSurface); } - copyRectClip( pos_blind, faceBuffer, screenSurface); - if (withVoices == 0) - centerText(said, 310, 71); + centerText(said, 260, 71); updateScreen(); pause(2); p++; - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); } void DrasculaEngine::talk_hacker(int index) { char filename[20]; sprintf(filename, "d%i.als", index); - const char *said = _textd[_lang][index]; - int length = strlen(said); + const char *said = _textd[index]; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); color_abc(kColorYellow); @@ -634,13 +642,13 @@ void DrasculaEngine::talk_hacker(int index) { if (withVoices == 0) centerText(said, 156, 170); updateScreen(); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); } void DrasculaEngine::talk_werewolf(int index) { char filename[20]; sprintf(filename, "L%i.als", index); - const char *said = _textl[_lang][index]; + const char *said = _textl[index]; int x_talk[9] = {52, 79, 106, 133, 160, 187, 214, 241, 268}; int coords[7] = { 136, 198, 81, 26, 24, 203, 78 }; @@ -651,7 +659,7 @@ void DrasculaEngine::talk_werewolf(int index) { void DrasculaEngine::talk_mus(int index) { char filename[20]; sprintf(filename, "E%i.als", index); - const char *said = _texte[_lang][index]; + const char *said = _texte[index]; int x_talk[8] = { 16, 35, 54, 73, 92, 111, 130, 149}; int coords[7] = { 156, 190, 64, 18, 24, 197, 64 }; @@ -663,7 +671,6 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker int x_talk[8] = {112, 138, 164, 190, 216, 242, 268, 294}; int x_talk2[5] = {122, 148, 174, 200, 226}; int face; - int length = strlen(said); flags[1] = 1; @@ -683,7 +690,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker else face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (talkerType == 0) @@ -703,10 +710,10 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); flags[1] = 0; - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); updateScreen(); } @@ -714,10 +721,9 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker void DrasculaEngine::talk_bj_bed(int index) { char filename[20]; sprintf(filename, "BJ%i.als", index); - const char *said = _textbj[_lang][index]; + const char *said = _textbj[index]; int x_talk[5] = {51, 101, 151, 201, 251}; int face; - int length = strlen(said); color_abc(kColorWhite); @@ -726,7 +732,7 @@ void DrasculaEngine::talk_bj_bed(int index) { do { face = _rnd->getRandomNumber(4); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); @@ -741,7 +747,7 @@ void DrasculaEngine::talk_bj_bed(int index) { updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); updateRoom(); updateScreen(); @@ -750,11 +756,9 @@ void DrasculaEngine::talk_bj_bed(int index) { void DrasculaEngine::talk_htel(int index) { char filename[20]; sprintf(filename, "%i.als", index); - const char *said = _text[_lang][index]; - char *faceBuffer; + const char *said = _text[index]; int x_talk[3] = {1, 94, 187}; int face, curScreen; - int length = strlen(said); color_abc(kColorYellow); @@ -764,25 +768,23 @@ void DrasculaEngine::talk_htel(int index) { face = _rnd->getRandomNumber(2); curScreen = _rnd->getRandomNumber(2); + copyBackground(); + if (face == 0 && curScreen == 0) - faceBuffer = (char *)drawSurface3; + copyBackground(x_talk[face], 1, 45, 24, 92, 108, drawSurface3, screenSurface); else if (curScreen == 1) - faceBuffer = (char *)frontSurface; + copyBackground(x_talk[face], 1, 45, 24, 92, 108, frontSurface, screenSurface); else - faceBuffer = (char *)backSurface; - - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - - copyBackground(x_talk[face], 1, 45, 24, 92, 108, (byte *)faceBuffer, screenSurface); - + copyBackground(x_talk[face], 1, 45, 24, 92, 108, backSurface, screenSurface); + if (withVoices == 0) centerText(said, 90, 50); updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateScreen(); } @@ -790,7 +792,6 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha int talkOffset = 1; int y_mask_talk = 170; int p, face = 0; - int length = strlen(said); char buf[2]; color_abc(kColorYellow); @@ -808,7 +809,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha strncpy(buf, &syncChar[p], 1); face = atoi(buf); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); if (currentChapter == 2) @@ -863,7 +864,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha p++; pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); if (currentChapter == 1 && musicStatus() == 0 && flags[11] == 0) playMusic(roomMusic); @@ -871,12 +872,11 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha playMusic(roomMusic); } -void DrasculaEngine::talk_baul(int index) { +void DrasculaEngine::talk_trunk(int index) { char filename[20]; sprintf(filename, "d%i.als", index); - const char *said = _text[_lang][index]; + const char *said = _text[index]; int face = 0, cara_antes; - int length = strlen(said); cara_antes = flags[19]; @@ -896,57 +896,21 @@ void DrasculaEngine::talk_baul(int index) { updateScreen(); pause(4); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); flags[19] = cara_antes; updateRoom(); updateScreen(); } -void DrasculaEngine::talk_dr_grande(int index) { - char filename[20]; - sprintf(filename, "D%i.als", index); - const char *said = _textd[_lang][index]; - int x_talk[4] = {47, 93, 139, 185}; - int face; - int l = 0; - int length = strlen(said); - - color_abc(kColorRed); - - talkInit(filename); - - do { - face = _rnd->getRandomNumber(3); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); - copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface); - copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface); - l++; - if (l == 7) - l = 0; - - if (withVoices == 0) - centerText(said, 191, 69); - - updateScreen(); - - pause(3); - - byte key = getScan(); - if (key == Common::KEYCODE_ESCAPE) - term_int = 1; - } while (!isTalkFinished(&length)); -} - void DrasculaEngine::talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface) { int face; - int length = strlen(said); talkInit(filename); do { face = _rnd->getRandomNumber(faceCount - 1); - copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); + copyBackground(); updateRefresh_pre(); copyBackground(faces[face], coords[0], coords[1], coords[2], coords[3], coords[4], surface, screenSurface); @@ -959,7 +923,27 @@ void DrasculaEngine::talk_generic(const char* said, const char* filename, int* f updateScreen(); pause(3); - } while (!isTalkFinished(&length)); + } while (!isTalkFinished()); + + updateRoom(); + updateScreen(); +} + + +void DrasculaEngine::grr() { + color_abc(kColorDarkGreen); + + playFile("s10.als"); + + updateRoom(); + copyBackground(253, 110, 150, 65, 20, 30, drawSurface3, screenSurface); + + if (withVoices == 0) + centerText("groaaarrrrgghhhh!", 153, 65); + + updateScreen(); + + while (!isTalkFinished()); updateRoom(); updateScreen(); diff --git a/engines/engine.cpp b/engines/engine.cpp index 757a77f82b..1d3368b10d 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -36,7 +36,10 @@ #include "common/savefile.h" #include "common/system.h" #include "gui/message.h" +#include "gui/newgui.h" #include "sound/mixer.h" +#include "engines/dialogs.h" +#include "engines/metaengine.h" #ifdef _WIN32_WCE extern bool isSmartphone(void); @@ -53,8 +56,9 @@ Engine::Engine(OSystem *syst) _eventMan(_system->getEventManager()), _saveFileMan(_system->getSavefileManager()), _targetName(ConfMan.getActiveDomainName()), - _gameDataPath(ConfMan.get("path")), - _pauseLevel(0) { + _gameDataDir(ConfMan.get("path")), + _pauseLevel(0), + _mainMenuDialog(NULL) { g_engine = this; _autosavePeriod = ConfMan.getInt("autosave_period"); @@ -72,7 +76,8 @@ Engine::Engine(OSystem *syst) Engine::~Engine() { _mixer->stopAll(); - + + delete _mainMenuDialog; g_engine = NULL; } @@ -145,12 +150,12 @@ void Engine::checkCD() { char buffer[MAXPATHLEN]; int i; - if (strlen(_gameDataPath.c_str()) == 0) { + if (_gameDataDir.getPath().empty()) { // That's it! I give up! if (getcwd(buffer, MAXPATHLEN) == NULL) return; } else - strncpy(buffer, _gameDataPath.c_str(), MAXPATHLEN); + strncpy(buffer, _gameDataDir.getPath().c_str(), MAXPATHLEN); for (i = 0; i < MAXPATHLEN - 1; i++) { if (buffer[i] == '\\') @@ -210,3 +215,50 @@ void Engine::pauseEngineIntern(bool pause) { // By default, just (un)pause all digital sounds _mixer->pauseAll(pause); } + +void Engine::mainMenuDialog() { + if (!_mainMenuDialog) + _mainMenuDialog = new MainMenuDialog(this); + runDialog(*_mainMenuDialog); + syncSoundSettings(); +} + +int Engine::runDialog(Dialog &dialog) { + + pauseEngine(true); + + int result = dialog.runModal(); + + pauseEngine(false); + + return result; +} + +void Engine::syncSoundSettings() { + + // Sync the engine with the config manager + int soundVolumeMusic = ConfMan.getInt("music_volume"); + int soundVolumeSFX = ConfMan.getInt("sfx_volume"); + int soundVolumeSpeech = ConfMan.getInt("speech_volume"); + + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech); +} + +void Engine::quitGame() { + Common::Event event; + + event.type = Common::EVENT_QUIT; + _eventMan->pushEvent(event); +} + +bool Engine::hasFeature(int f) { + const EnginePlugin *plugin = 0; + Common::String gameid = ConfMan.get("gameid"); + gameid.toLowercase(); + EngineMan.findGame(gameid, &plugin); + + return ( (*plugin)->hasFeature((MetaEngine::MetaEngineFeature)f) ); +} + diff --git a/engines/engine.h b/engines/engine.h index 73d529cc62..81e4e6187c 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -25,10 +25,13 @@ #ifndef ENGINES_ENGINE_H #define ENGINES_ENGINE_H +#include "common/events.h" +#include "common/fs.h" #include "common/scummsys.h" #include "common/str.h" class OSystem; + namespace Audio { class Mixer; } @@ -39,8 +42,11 @@ namespace Common { } namespace GUI { class Debugger; + class Dialog; } +using GUI::Dialog; + class Engine { public: OSystem *_system; @@ -50,9 +56,13 @@ public: protected: Common::EventManager *_eventMan; Common::SaveFileManager *_saveFileMan; + + Dialog *_mainMenuDialog; + virtual int runDialog(Dialog &dialog); const Common::String _targetName; // target name for saves - const Common::String _gameDataPath; + + const Common::FilesystemNode _gameDataDir; private: /** @@ -82,7 +92,7 @@ public: * Start the main engine loop. * The return value is not yet used, but could indicate whether the user * wants to return to the launch or to fully quit ScummVM. - * @return a result code + * @return 0 for success, else an error code. */ virtual int go() = 0; @@ -109,10 +119,32 @@ public: void pauseEngine(bool pause); /** + * Quit the engine, sends a Quit event to the Event Manager + */ + void quitGame(); + + /** * Return whether the engine is currently paused or not. */ bool isPaused() const { return _pauseLevel != 0; } + /** + * Return whether or not the ENGINE should quit + */ + bool quit() const { return (_eventMan->shouldQuit() || _eventMan->shouldRTL()); } + + /** Run the Global Main Menu Dialog + */ + virtual void mainMenuDialog(); + + /** Sync the engine's sound settings with the config manager + */ + virtual void syncSoundSettings(); + + /** Determine whether the engine supports the specified MetaEngine feature + */ + virtual bool hasFeature(int f); + public: /** Setup the backend's graphics mode. */ diff --git a/engines/game.cpp b/engines/game.cpp new file mode 100644 index 0000000000..b3cb140e0a --- /dev/null +++ b/engines/game.cpp @@ -0,0 +1,116 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "engines/game.h" +#include "base/plugins.h" +#include "graphics/surface.h" + + +const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) { + const PlainGameDescriptor *g = list; + while (g->gameid) { + if (0 == scumm_stricmp(gameid, g->gameid)) + return g; + g++; + } + return 0; +} + +void GameDescriptor::updateDesc(const char *extra) { + // TODO: The format used here (LANG/PLATFORM/EXTRA) is not set in stone. + // We may want to change the order (PLATFORM/EXTRA/LANG, anybody?), or + // the seperator (instead of '/' use ', ' or ' '). + const bool hasCustomLanguage = (language() != Common::UNK_LANG); + const bool hasCustomPlatform = (platform() != Common::kPlatformUnknown); + const bool hasExtraDesc = (extra && extra[0]); + + // Adapt the description string if custom platform/language is set. + if (hasCustomLanguage || hasCustomPlatform || hasExtraDesc) { + Common::String descr = description(); + + descr += " ("; + if (hasExtraDesc) + descr += extra; + if (hasCustomPlatform) { + if (hasExtraDesc) + descr += "/"; + descr += Common::getPlatformDescription(platform()); + } + if (hasCustomLanguage) { + if (hasExtraDesc || hasCustomPlatform) + descr += "/"; + descr += Common::getLanguageDescription(language()); + } + descr += ")"; + setVal("description", descr); + } +} + +void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { + if (_thumbnail.get() == t) + return; + + _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter()); +} + +bool SaveStateDescriptor::getBool(const Common::String &key) const { + if (contains(key)) { + Common::String value = getVal(key); + if (value.equalsIgnoreCase("true") || + value.equalsIgnoreCase("yes") || + value.equals("1")) + return true; + if (value.equalsIgnoreCase("false") || + value.equalsIgnoreCase("no") || + value.equals("0")) + return false; + error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'", + save_slot().c_str(), description().c_str(), value.c_str(), key.c_str()); + } + return false; +} + +void SaveStateDescriptor::setDeletableFlag(bool state) { + setVal("is_deletable", state ? "true" : "false"); +} + +void SaveStateDescriptor::setSaveDate(int year, int month, int day) { + char buffer[32]; + snprintf(buffer, 32, "%.2d.%.2d.%.4d", day, month, year); + setVal("save_date", buffer); +} + +void SaveStateDescriptor::setSaveTime(int hour, int min) { + char buffer[32]; + snprintf(buffer, 32, "%.2d:%.2d", hour, min); + setVal("save_time", buffer); +} + +void SaveStateDescriptor::setPlayTime(int hours, int minutes) { + char buffer[32]; + snprintf(buffer, 32, "%.2d:%.2d", hours, minutes); + setVal("play_time", buffer); +} + diff --git a/engines/game.h b/engines/game.h new file mode 100644 index 0000000000..a1eed7acd9 --- /dev/null +++ b/engines/game.h @@ -0,0 +1,210 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef ENGINES_GAME_H +#define ENGINES_GAME_H + +#include "common/str.h" +#include "common/array.h" +#include "common/hash-str.h" +#include "common/ptr.h" + +namespace Graphics { + struct Surface; +} + +/** + * A simple structure used to map gameids (like "monkey", "sword1", ...) to + * nice human readable and descriptive game titles (like "The Secret of Monkey Island"). + * This is a plain struct to make it possible to declare NULL-terminated C arrays + * consisting of PlainGameDescriptors. + */ +struct PlainGameDescriptor { + const char *gameid; + const char *description; +}; + +/** + * Given a list of PlainGameDescriptors, returns the first PlainGameDescriptor + * matching the given gameid. If not match is found return 0. + * The end of the list must marked by a PlainGameDescriptor with gameid equal to 0. + */ +const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list); + +/** + * A hashmap describing details about a given game. In a sense this is a refined + * version of PlainGameDescriptor, as it also contains a gameid and a description string. + * But in addition, platform and language settings, as well as arbitrary other settings, + * can be contained in a GameDescriptor. + * This is an essential part of the glue between the game engines and the launcher code. + */ +class GameDescriptor : public Common::StringMap { +public: + GameDescriptor() { + setVal("gameid", ""); + setVal("description", ""); + } + + GameDescriptor(const PlainGameDescriptor &pgd) { + setVal("gameid", pgd.gameid); + setVal("description", pgd.description); + } + + GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l = Common::UNK_LANG, + Common::Platform p = Common::kPlatformUnknown) { + setVal("gameid", g); + setVal("description", d); + if (l != Common::UNK_LANG) + setVal("language", Common::getLanguageCode(l)); + if (p != Common::kPlatformUnknown) + setVal("platform", Common::getPlatformCode(p)); + } + + /** + * Update the description string by appending (LANG/PLATFORM/EXTRA) to it. + */ + void updateDesc(const char *extra = 0); + + Common::String &gameid() { return getVal("gameid"); } + Common::String &description() { return getVal("description"); } + const Common::String &gameid() const { return getVal("gameid"); } + const Common::String &description() const { return getVal("description"); } + Common::Language language() const { return contains("language") ? Common::parseLanguage(getVal("language")) : Common::UNK_LANG; } + Common::Platform platform() const { return contains("platform") ? Common::parsePlatform(getVal("platform")) : Common::kPlatformUnknown; } + + const Common::String &preferredtarget() const { + return contains("preferredtarget") ? getVal("preferredtarget") : getVal("gameid"); + } +}; + +/** List of games. */ +class GameList : public Common::Array<GameDescriptor> { +public: + GameList() {} + GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {} + GameList(const PlainGameDescriptor *g) { + while (g->gameid) { + push_back(GameDescriptor(g->gameid, g->description)); + g++; + } + } +}; + +/** + * A hashmap describing details about a given save state. + * TODO + * Guaranteed to contain save_slot, filename and description values. + * Additional ideas: Playtime, creation date, thumbnail, ... + */ +class SaveStateDescriptor : public Common::StringMap { +protected: + Common::SharedPtr<Graphics::Surface> _thumbnail; // can be 0 + +public: + SaveStateDescriptor() : _thumbnail() { + setVal("save_slot", "-1"); // FIXME: default to 0 (first slot) or to -1 (invalid slot) ? + setVal("description", ""); + setVal("filename", ""); + } + + SaveStateDescriptor(int s, const Common::String &d, const Common::String &f) : _thumbnail() { + char buf[16]; + sprintf(buf, "%d", s); + setVal("save_slot", buf); + setVal("description", d); + setVal("filename", f); + } + + SaveStateDescriptor(const Common::String &s, const Common::String &d, const Common::String &f) : _thumbnail() { + setVal("save_slot", s); + setVal("description", d); + setVal("filename", f); + } + + /** The saveslot id, as it would be passed to the "-x" command line switch. */ + Common::String &save_slot() { return getVal("save_slot"); } + + /** The saveslot id, as it would be passed to the "-x" command line switch (read-only variant). */ + const Common::String &save_slot() const { return getVal("save_slot"); } + + /** A human readable description of the save state. */ + Common::String &description() { return getVal("description"); } + + /** A human readable description of the save state (read-only variant). */ + const Common::String &description() const { return getVal("description"); } + + /** The filename of the savestate, for use with the SaveFileManager API. */ + Common::String &filename() { return getVal("filename"); } + + /** The filename of the savestate, for use with the SaveFileManager API (read-only variant). */ + const Common::String &filename() const { return getVal("filename"); } + + /** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */ + + /** + * Returns the value of a given key as boolean. + * It accepts 'true', 'yes' and '1' for true and + * 'false', 'no' and '0' for false. + * (FIXME:) On unknown value it errors out ScummVM. + * On unknown key it returns false as default. + */ + bool getBool(const Common::String &key) const; + + /** + * Sets the 'is_deletable' key, which indicates, if the + * given savestate is safe for deletion. + */ + void setDeletableFlag(bool state); + + /** + * Return a thumbnail graphics surface representing the savestate visually + * This is usually a scaled down version of the game graphics. The size + * should be either 160x100 or 160x120 pixels, depending on the aspect + * ratio of the game. If another ratio is required, contact the core team. + */ + const Graphics::Surface *getThumbnail() const { return _thumbnail.get(); } + + void setThumbnail(Graphics::Surface *t); + + /** + * Sets the 'save_date' key properly, based on the given values + */ + void setSaveDate(int year, int month, int day); + + /** + * Sets the 'save_time' key properly, based on the given values + */ + void setSaveTime(int hour, int min); + + /** + * Sets the 'play_time' key properly, based on the given values + */ + void setPlayTime(int hours, int minutes); +}; + +/** List of savestates. */ +typedef Common::Array<SaveStateDescriptor> SaveStateList; + +#endif diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index bcf566d134..d154a01de9 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -62,38 +62,40 @@ DataStream::~DataStream() { } } -uint32 DataStream::pos() const { +int32 DataStream::pos() const { if (_stream) return _stream->pos(); - uint32 resPos = _io->getChunkPos(_handle); - if (resPos != 0xFFFFFFFF) + int32 resPos = _io->getChunkPos(_handle); + if (resPos != -1) return resPos; return _io->file_getHandle(_handle)->pos(); } -uint32 DataStream::size() const { +int32 DataStream::size() const { if (_stream) return _stream->size(); return _size; } -void DataStream::seek(int32 offset, int whence) { +bool DataStream::seek(int32 offset, int whence) { if (_stream) - _stream->seek(offset, whence); + return _stream->seek(offset, whence); else if ((_handle < 50) || (_handle >= 128)) - _io->file_getHandle(_handle)->seek(offset, whence); - else - _io->seekChunk(_handle, offset, whence); + return _io->file_getHandle(_handle)->seek(offset, whence); + else { + _io->seekChunk(_handle, offset, whence); + return true; + } } bool DataStream::eos() const { if (_stream) return _stream->eos(); - return pos() >= size(); + return pos() >= size(); // FIXME (eos definition change) } uint32 DataStream::read(void *dataPtr, uint32 dataSize) { diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 4b4c79d1eb..c67dc89df8 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -45,10 +45,10 @@ public: DataStream(byte *buf, uint32 dSize, bool dispose = true); virtual ~DataStream(); - virtual uint32 pos() const; - virtual uint32 size() const; + virtual int32 pos() const; + virtual int32 size() const; - virtual void seek(int32 offset, int whence = SEEK_SET); + virtual bool seek(int32 offset, int whence = SEEK_SET); virtual bool eos() const; diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 63a0f8f45b..2b0c015677 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -57,6 +57,7 @@ static const PlainGameDescriptor gobGames[] = { {"inca2", "Inca II: Wiracocha"}, {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"}, {"dynasty", "The Last Dynasty"}, + {"urban", "Urban Runner"}, {0, 0} }; @@ -277,6 +278,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesNone, "intro" }, + { + { + "gob1", + "Interactive Demo", + AD_ENTRY1s("intro.stk", "a796096280d5efd48cf8e7dfbe426eb5", 193595), + UNK_LANG, + kPlatformPC, + Common::ADGF_DEMO + }, + kGameTypeGob1, + kFeaturesNone, + "intro" + }, { // Supplied by raina in the forums { "gob1", @@ -900,6 +914,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesNone, "intro" }, + { // Supplied by kizkoool in bugreport #2089734 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "00f6b4e2ee26e5c40b488e2df5adcf03", 3975580), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeBargon, + kFeaturesNone, + "intro" + }, { // Supplied by glorfindel in bugreport #1722142 { "bargon", @@ -1043,6 +1070,84 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesCD, "intro" }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { // Supplied by SiRoCs in bug report #2093672 + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904), + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, { { "lostintime", @@ -1190,6 +1295,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeaturesAdlib, "intro" }, + { // Supplied by SiRoCs in bug report #2098621 + { + "gob3", + "", + AD_ENTRY1s("intro.stk", "d3b72938fbbc8159198088811f9e6d19", 160382), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesAdlib, + "intro" + }, { { "gob3", @@ -1762,6 +1880,19 @@ static const GOBGameDescription gameDescriptions[] = { kFeatures640, "intro" }, + { // Supplied by goodoldgeorg in bug report #2098838 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "08a96bf061af1fa4f75c6a7cc56b60a4", 20734979), + PL_POL, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, { { "dynasty", @@ -1771,7 +1902,7 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - kGameTypeWoodruff, + kGameTypeDynasty, kFeatures640, "intro" }, @@ -1784,7 +1915,20 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - kGameTypeWoodruff, + kGameTypeDynasty, + kFeatures640, + "intro" + }, + { + { + "urban", + "", + AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeUrban, kFeatures640, "intro" }, @@ -1972,9 +2116,15 @@ public: return "Goblins Games (C) Coktel Vision"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; }; +bool GobMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL); +} + bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc; if (gd) { diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 8a7de9bdaa..7136646018 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -323,7 +323,38 @@ void Draw::adjustCoords(char adjust, int16 *coord1, int16 *coord2) { } } -void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, +int Draw::stringLength(const char *str, int16 fontIndex) { + static const int8 dword_8F74C[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if ((fontIndex < 0) || (fontIndex > 7) || !_fonts[fontIndex]) + return 0; + + int len = 0; + + if (_vm->_global->_language == 10) { + + for (int i = 0; str[i] != 0; i++) { + if (((unsigned char) str[i+1]) < 128) { + len += dword_8F74C[4]; + i++; + } else + len += _fonts[fontIndex]->itemWidth; + } + + } else { + + if (_fonts[fontIndex]->extraData) + while (*str != 0) + len += *(_fonts[fontIndex]->extraData + (*str++ - _fonts[fontIndex]->startItem)); + else + len = (strlen(str) * _fonts[fontIndex]->itemWidth); + + } + + return len; +} + +void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, int16 transp, SurfaceDesc *dest, Video::FontDesc *font) { while (*str != '\0') { @@ -337,7 +368,7 @@ void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, } void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, - int16 bottom, char *str, int16 fontIndex, int16 color) { + int16 bottom, const char *str, int16 fontIndex, int16 color) { adjustCoords(1, &left, &top); adjustCoords(1, &right, &bottom); diff --git a/engines/gob/draw.h b/engines/gob/draw.h index 9ba589aa53..897208a42d 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -69,7 +69,7 @@ public: int16 _destSurface; char _letterToPrint; - char *_textToPrint; + const char *_textToPrint; int16 _backDeltaX; int16 _backDeltaY; @@ -146,10 +146,11 @@ public: void adjustCoords(char adjust, uint16 *coord1, uint16 *coord2) { adjustCoords(adjust, (int16 *) coord1, (int16 *) coord2); } - void drawString(char *str, int16 x, int16 y, int16 color1, int16 color2, + int stringLength(const char *str, int16 fontIndex); + void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2, int16 transp, SurfaceDesc *dest, Video::FontDesc *font); void printTextCentered(int16 id, int16 left, int16 top, int16 right, - int16 bottom, char *str, int16 fontIndex, int16 color); + int16 bottom, const char *str, int16 fontIndex, int16 color); int32 getSpriteRectSize(int16 index); void forceBlit(bool backwards = false); diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp index 66deea8ec4..0ecbc81358 100644 --- a/engines/gob/game_v1.cpp +++ b/engines/gob/game_v1.cpp @@ -63,7 +63,7 @@ void Game_v1::playTot(int16 skipPlay) { strcpy(savedTotName, _curTotFile); if (skipPlay <= 0) { - while (!_vm->_quitRequested) { + while (!_vm->quit()) { for (int i = 0; i < 4; i++) { _vm->_draw->_fontToSprite[i].sprite = -1; _vm->_draw->_fontToSprite[i].base = -1; @@ -997,7 +997,7 @@ void Game_v1::collisionsBlock(void) { WRITE_VAR(16, 0); _activeCollResId = 0; } - while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->_quitRequested); + while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->quit()); if (((uint16) _activeCollResId & ~0x8000) == collResId) { collStackPos = 0; diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index adf75176ab..7d9419b592 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -70,7 +70,7 @@ void Game_v2::playTot(int16 skipPlay) { strcpy(savedTotName, _curTotFile); if (skipPlay <= 0) { - while (!_vm->_quitRequested) { + while (!_vm->quit()) { if (_vm->_inter->_variables) _vm->_draw->animateCursor(4); @@ -438,7 +438,7 @@ int16 Game_v2::checkCollisions(byte handleMouse, int16 deltaTime, int16 *pResId, timeKey = _vm->_util->getTimeKey(); while (1) { - if (_vm->_inter->_terminate || _vm->_quitRequested) { + if (_vm->_inter->_terminate || _vm->quit()) { if (handleMouse) _vm->_draw->blitCursor(); return 0; @@ -1043,7 +1043,7 @@ void Game_v2::collisionsBlock(void) { WRITE_VAR(16, 0); _activeCollResId = 0; } - while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->_quitRequested); + while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->quit()); if ((_activeCollResId & 0xFFF) == collResId) { collStackPos = 0; @@ -1465,7 +1465,7 @@ int16 Game_v2::inputArea(int16 xPos, int16 yPos, int16 width, int16 height, key = checkCollisions(handleMouse, -300, collResId, collIndex); if ((key != 0) || (*collResId != 0) || - _vm->_inter->_terminate || _vm->_quitRequested) + _vm->_inter->_terminate || _vm->quit()) break; if (*pTotTime > 0) { @@ -1479,7 +1479,7 @@ int16 Game_v2::inputArea(int16 xPos, int16 yPos, int16 width, int16 height, } if ((key == 0) || (*collResId != 0) || - _vm->_inter->_terminate || _vm->_quitRequested) + _vm->_inter->_terminate || _vm->quit()) return 0; switch (key) { diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 34443251d8..7e364e891d 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -24,7 +24,6 @@ */ #include "common/endian.h" -#include "common/events.h" #include "base/plugins.h" #include "common/config-manager.h" @@ -62,7 +61,9 @@ const Common::Language GobEngine::_gobToScummVMLang[] = { Common::EN_USA, Common::NL_NLD, Common::KO_KOR, - Common::HB_ISR + Common::HB_ISR, + Common::PT_BRA, + Common::JA_JPN }; GobEngine::GobEngine(OSystem *syst) : Engine(syst) { @@ -82,7 +83,6 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); _copyProtection = ConfMan.getBool("copy_protection"); - _quitRequested = false; Common::addSpecialDebugLevel(kDebugFuncOp, "FuncOpcodes", "Script FuncOpcodes debug level"); Common::addSpecialDebugLevel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level"); @@ -115,12 +115,8 @@ int GobEngine::go() { return 0; } -void GobEngine::shutdown() { - _quitRequested = true; -} - const char *GobEngine::getLangDesc(int16 language) const { - if ((language < 0) || (language > 8)) + if ((language < 0) || (language > 10)) language = 2; return Common::getLanguageDescription(_gobToScummVMLang[language]); } @@ -244,6 +240,12 @@ int GobEngine::init() { case Common::HB_ISR: _global->_language = 8; break; + case Common::PT_BRA: + _global->_language = 9; + break; + case Common::JA_JPN: + _global->_language = 10; + break; default: // Default to English _global->_language = 2; @@ -387,6 +389,34 @@ bool GobEngine::initGameParts() { _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); break; + case kGameTypeDynasty: + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v5(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v4(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); + break; + + case kGameTypeUrban: + _init = new Init_v3(this); + _video = new Video_v6(this); + _inter = new Inter_v6(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v4(this); + _goblin = new Goblin_v4(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); + break; + default: deinitGameParts(); return false; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 041658baea..39950e3261 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -93,7 +93,9 @@ enum GameType { kGameTypeBargon, kGameTypeWeen, kGameTypeLostInTime, - kGameTypeInca2 + kGameTypeInca2, + kGameTypeDynasty, + kGameTypeUrban }; enum Features { @@ -209,7 +211,6 @@ public: char *_startTot0; bool _copyProtection; bool _noMusic; - bool _quitRequested; Global *_global; Util *_util; @@ -229,8 +230,6 @@ public: SaveLoad *_saveLoad; VideoPlayer *_vidPlayer; - void shutdown(); - const char *getLangDesc(int16 language) const; void validateLanguage(); void validateVideoMode(int16 videoMode); diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index 5add0b9cea..55758cdfdc 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -652,7 +652,7 @@ void Goblin::adjustDest(int16 posX, int16 posY) { if ((_vm->_map->getPass(_pressedMapX, _pressedMapY) == 0) && ((_gobAction == 0) || - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0))) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0))) { resDelta = -1; resDeltaDir = 0; @@ -727,17 +727,17 @@ void Goblin::adjustDest(int16 posX, int16 posY) { void Goblin::adjustTarget(void) { if ((_gobAction == 4) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0)) { if ((_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) { _pressedMapY--; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) { _pressedMapX++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) { _pressedMapY--; _pressedMapX++; } @@ -747,7 +747,7 @@ void Goblin::adjustTarget(void) { } void Goblin::targetDummyItem(Gob_Object *gobDesc) { - if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 && + if (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0 && _vm->_map->getPass(_pressedMapX, _pressedMapY) == 1) { if (gobDesc->curLookDir == 0) { _vm->_map->_itemPoses[0].x = _pressedMapX; @@ -771,7 +771,7 @@ void Goblin::targetItem(void) { Gob_Object *itemDesc; if ((_gobAction == 3) || (_gobAction == 4)) { - items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX]; + items = _vm->_map->getItem(_pressedMapX, _pressedMapY); if ((_gobAction == 4) && ((items & 0xFF00) != 0) && (_objects[_itemToObject[(items & 0xFF00) >> 8]]->pickable == 1)) { _destItemId = (items & 0xFF00) >> 8; @@ -802,40 +802,40 @@ void Goblin::targetItem(void) { _gobDestX = _vm->_map->_itemPoses[_destItemId].x; } else if ((items & 0xFF00) != 0) { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } - if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] & 0xFF00) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) & 0xFF00) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; } } else { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; @@ -843,8 +843,8 @@ void Goblin::targetItem(void) { } if (_pressedMapY < (_vm->_map->_mapHeight-1)) { - if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX]) == - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1)) == + (_vm->_map->getItem(_pressedMapX, _pressedMapY))) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; @@ -931,37 +931,37 @@ void Goblin::moveFindItem(int16 posX, int16 posY) { _pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1); _pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1); - if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) && (i < 20)) { + if ((_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0) && (i < 20)) { if ((_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) != 0)) { _pressedMapY++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY + 1) != 0)) { _pressedMapX++; _pressedMapY++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) { _pressedMapX++; } else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) && (_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) { + (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) { _pressedMapX++; _pressedMapY--; } else if ((_pressedMapY > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) { + (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) { _pressedMapY--; } else if ((_pressedMapY > 0) && (_pressedMapX > 0) && - (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY - 1) != 0)) { _pressedMapY--; _pressedMapX--; } else if ((_pressedMapX > 0) && - (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) != 0)) { _pressedMapX--; } else if ((_pressedMapX > 0) && (_pressedMapY < (_vm->_map->_mapHeight - 1)) && - (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX - 1] != 0)) { + (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY + 1) != 0)) { _pressedMapX--; _pressedMapY++; } @@ -1384,11 +1384,11 @@ void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) { for (int y = 0; y < _vm->_map->_mapHeight; y++) { for (int x = 0; x < _vm->_map->_mapWidth; x++) { if (_itemByteFlag == 1) { - if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPocket) - _vm->_map->_itemsMap[y][x] &= 0xFF; + if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPocket) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF); } else { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPocket) - _vm->_map->_itemsMap[y][x] &= 0xFF00; + if ((_vm->_map->getItem(x, y) & 0xFF) == idToPocket) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00); } } } @@ -1494,18 +1494,16 @@ void Goblin::swapItems(int16 indexToPick, int16 idToPick) { if (_itemByteFlag == 0) { for (y = 0; y < _vm->_map->_mapHeight; y++) { for (x = 0; x < _vm->_map->_mapWidth; x++) { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPick) - _vm->_map->_itemsMap[y][x] = - (_vm->_map->_itemsMap[y][x] & 0xFF00) + idToPlace; + if ((_vm->_map->getItem(x, y) & 0xFF) == idToPick) + _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF00) + idToPlace); } } } else { for (y = 0; y < _vm->_map->_mapHeight; y++) { for (x = 0; x < _vm->_map->_mapWidth; x++) { - if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPick) - _vm->_map->_itemsMap[y][x] = - (_vm->_map->_itemsMap[y][x] & 0xFF) + (idToPlace << 8); + if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPick) + _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF) + (idToPlace << 8)); } } } diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 02e7f99cbd..4973bd756d 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -259,7 +259,7 @@ void Inter::funcBlock(int16 retFlag) { if (executeFuncOpcode(cmd2, cmd, params)) return; - if (_vm->_quitRequested) + if (_vm->quit()) break; if (_break) { @@ -279,7 +279,7 @@ void Inter::funcBlock(int16 retFlag) { void Inter::callSub(int16 retFlag) { byte block; - while (!_vm->_quitRequested && _vm->_global->_inter_execPtr && + while (!_vm->quit() && _vm->_global->_inter_execPtr && (_vm->_global->_inter_execPtr != _vm->_game->_totFileData)) { block = *_vm->_global->_inter_execPtr; diff --git a/engines/gob/inter.h b/engines/gob/inter.h index b684be6c07..fe31722c6c 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -529,6 +529,102 @@ protected: void o4_playVmdOrMusic(); }; +class Inter_v5 : public Inter_v4 { +public: + Inter_v5(GobEngine *vm); + virtual ~Inter_v5() {} + +protected: + typedef void (Inter_v5::*OpcodeDrawProcV5)(); + typedef bool (Inter_v5::*OpcodeFuncProcV5)(OpFuncParams &); + typedef void (Inter_v5::*OpcodeGoblinProcV5)(OpGobParams &); + struct OpcodeDrawEntryV5 { + OpcodeDrawProcV5 proc; + const char *desc; + }; + struct OpcodeFuncEntryV5 { + OpcodeFuncProcV5 proc; + const char *desc; + }; + struct OpcodeGoblinEntryV5 { + OpcodeGoblinProcV5 proc; + const char *desc; + }; + const OpcodeDrawEntryV5 *_opcodesDrawV5; + const OpcodeFuncEntryV5 *_opcodesFuncV5; + const OpcodeGoblinEntryV5 *_opcodesGoblinV5; + static const int _goblinFuncLookUp[][2]; + + virtual void setupOpcodes(); + virtual void executeDrawOpcode(byte i); + virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); + virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); + virtual const char *getOpcodeDrawDesc(byte i); + virtual const char *getOpcodeFuncDesc(byte i, byte j); + virtual const char *getOpcodeGoblinDesc(int i); + + byte _byte_8AA14; + + void o5_deleteFile(); + + bool o5_istrlen(OpFuncParams ¶ms); + + void o5_spaceShooter(OpGobParams ¶ms); + void o5_getSystemCDSpeed(OpGobParams ¶ms); + void o5_getSystemRAM(OpGobParams ¶ms); + void o5_getSystemCPUSpeed(OpGobParams ¶ms); + void o5_getSystemDrawSpeed(OpGobParams ¶ms); + void o5_totalSystemSpecs(OpGobParams ¶ms); + void o5_saveSystemSpecs(OpGobParams ¶ms); + void o5_loadSystemSpecs(OpGobParams ¶ms); + + void o5_gob92(OpGobParams ¶ms); + void o5_gob95(OpGobParams ¶ms); + void o5_gob96(OpGobParams ¶ms); + void o5_gob97(OpGobParams ¶ms); + void o5_gob98(OpGobParams ¶ms); + void o5_gob100(OpGobParams ¶ms); + void o5_gob200(OpGobParams ¶ms); +}; + +class Inter_v6 : public Inter_v5 { +public: + Inter_v6(GobEngine *vm); + virtual ~Inter_v6() {} + +protected: + typedef void (Inter_v6::*OpcodeDrawProcV6)(); + typedef bool (Inter_v6::*OpcodeFuncProcV6)(OpFuncParams &); + typedef void (Inter_v6::*OpcodeGoblinProcV6)(OpGobParams &); + struct OpcodeDrawEntryV6 { + OpcodeDrawProcV6 proc; + const char *desc; + }; + struct OpcodeFuncEntryV6 { + OpcodeFuncProcV6 proc; + const char *desc; + }; + struct OpcodeGoblinEntryV6 { + OpcodeGoblinProcV6 proc; + const char *desc; + }; + const OpcodeDrawEntryV6 *_opcodesDrawV6; + const OpcodeFuncEntryV6 *_opcodesFuncV6; + const OpcodeGoblinEntryV6 *_opcodesGoblinV6; + static const int _goblinFuncLookUp[][2]; + + virtual void setupOpcodes(); + virtual void executeDrawOpcode(byte i); + virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); + virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); + virtual const char *getOpcodeDrawDesc(byte i); + virtual const char *getOpcodeFuncDesc(byte i, byte j); + virtual const char *getOpcodeGoblinDesc(int i); + + bool o6_loadCursor(OpFuncParams ¶ms); + bool o6_evaluateStore(OpFuncParams ¶ms); +}; + } // End of namespace Gob #endif // GOB_INTER_H diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index d493fb00d3..d23841efd6 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -750,7 +750,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { for (i = 320; i >= 0; i--) { _vm->_util->setScrollOffset(i, 0); if ((_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B) || - _vm->_quitRequested) { + _vm->quit()) { _vm->_palAnim->fade(0, -2, 0); _vm->_video->clearSurf(_vm->_draw->_frontSurface); memset((char *) _vm->_draw->_vgaPalette, 0, 768); @@ -760,7 +760,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { break; } } - if (!_vm->_quitRequested) + if (!_vm->quit()) _vm->_util->setScrollOffset(0, 0); surface = 0; if (VAR(57) == ((uint32) -1)) @@ -799,7 +799,7 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { _vm->_util->longDelay(_vm->_util->getRandom(200)); } if ((_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B) || - _vm->_quitRequested) { + _vm->quit()) { _vm->_sound->blasterStop(10); _vm->_palAnim->fade(0, -2, 0); _vm->_video->clearSurf(_vm->_draw->_frontSurface); diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 865d188a2e..1e01cd9048 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -1234,7 +1234,7 @@ bool Inter_v1::o1_repeatUntil(OpFuncParams ¶ms) { funcBlock(1); _vm->_global->_inter_execPtr = blockPtr + size + 1; flag = evalBoolResult(); - } while (!flag && !_break && !_terminate && !_vm->_quitRequested); + } while (!flag && !_break && !_terminate && !_vm->quit()); _nestLevel[0]--; @@ -1269,7 +1269,7 @@ bool Inter_v1::o1_whileDo(OpFuncParams ¶ms) { } else _vm->_global->_inter_execPtr += size; - if (_break || _terminate || _vm->_quitRequested) { + if (_break || _terminate || _vm->quit()) { _vm->_global->_inter_execPtr = blockPtr; _vm->_global->_inter_execPtr += size; break; @@ -2443,10 +2443,10 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) { int16 xPos = load16(); int16 yPos = load16(); - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) + params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8); else - params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos); } void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { @@ -2468,10 +2468,10 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { xPos = VAR(xPos); yPos = VAR(yPos); - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) - params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8); + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) + params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8); else - params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos]; + params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos); } void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { @@ -3025,88 +3025,88 @@ void Inter_v1::animPalette() { void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) { for (int y = 0; y < _vm->_map->_mapHeight; y++) { for (int x = 0; x < _vm->_map->_mapWidth; x++) { - if ((_vm->_map->_itemsMap[y][x] & 0xFF) == item) - _vm->_map->_itemsMap[y][x] &= 0xFF00; - else if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == item) - _vm->_map->_itemsMap[y][x] &= 0xFF; + if ((_vm->_map->getItem(x, y) & 0xFF) == item) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00); + else if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == item) + _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF); } } if (xPos < _vm->_map->_mapWidth - 1) { if (yPos > 0) { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos + 1] = - (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos - 1, + (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos + 1] = - (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos - 1, + (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF) + (item << 8)); } } else { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item; + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos][xPos + 1] = - (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos + 1, yPos, + (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8)); } } } else { if (yPos > 0) { - if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) || - ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0)) { + if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) || + ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0)) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item; + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); - _vm->_map->_itemsMap[yPos - 1][xPos] = - (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos - 1, + (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8)); } } else { - if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item; + if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) { + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item); } else { - _vm->_map->_itemsMap[yPos][xPos] = - (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8); + _vm->_map->setItem(xPos, yPos, + (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8)); } } } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 2f1d2ec0be..b245001653 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -24,6 +24,7 @@ */ #include "common/endian.h" + #include "sound/mixer.h" #include "sound/mods/infogrames.h" @@ -1489,7 +1490,7 @@ void Inter_v2::o2_scroll() { curX = startX; curY = startY; - while (!_vm->_quitRequested && ((curX != endX) || (curY != endY))) { + while (!_vm->quit() && ((curX != endX) || (curY != endY))) { curX = stepX > 0 ? MIN(curX + stepX, (int) endX) : MAX(curX + stepX, (int) endX); curY = stepY > 0 ? MIN(curY + stepY, (int) endY) : diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp new file mode 100644 index 0000000000..6df76bda4a --- /dev/null +++ b/engines/gob/inter_v5.cpp @@ -0,0 +1,1040 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/file.h" + +#include "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/draw.h" + +namespace Gob { + +#define OPCODE(x) _OPCODE(Inter_v5, x) + +const int Inter_v5::_goblinFuncLookUp[][2] = { + {0, 0}, + {1, 0}, + {80, 1}, + {81, 2}, + {82, 3}, + {83, 4}, + {84, 5}, + {85, 6}, + {86, 7}, + {87, 0}, + {88, 0}, + {89, 0}, + {90, 0}, + {91, 0}, + {92, 8}, + {93, 0}, + {94, 0}, + {95, 9}, + {96, 10}, + {97, 11}, + {98, 12}, + {99, 0}, + {100, 13}, + {200, 14}, + {30, 24}, + {32, 25}, + {33, 26}, + {34, 27}, + {35, 28}, + {36, 29}, + {37, 30}, + {40, 31}, + {41, 32}, + {42, 33}, + {43, 34}, + {44, 35}, + {50, 36}, + {52, 37}, + {53, 38}, + {100, 39}, + {152, 40}, + {200, 41}, + {201, 42}, + {202, 43}, + {203, 44}, + {204, 45}, + {250, 46}, + {251, 47}, + {252, 48}, + {500, 49}, + {502, 50}, + {503, 51}, + {600, 52}, + {601, 53}, + {602, 54}, + {603, 55}, + {604, 56}, + {605, 57}, + {1000, 58}, + {1001, 59}, + {1002, 60}, + {1003, 61}, + {1004, 62}, + {1005, 63}, + {1006, 64}, + {1008, 65}, + {1009, 66}, + {1010, 67}, + {1011, 68}, + {1015, 69}, + {2005, 70} +}; + +Inter_v5::Inter_v5(GobEngine *vm) : Inter_v4(vm) { + setupOpcodes(); +} + +void Inter_v5::setupOpcodes() { + static const OpcodeDrawEntryV5 opcodesDraw[256] = { + /* 00 */ + OPCODE(o1_loadMult), + OPCODE(o2_playMult), + OPCODE(o2_freeMultKeys), + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_initCursor), + /* 08 */ + OPCODE(o1_initCursorAnim), + OPCODE(o1_clearCursorAnim), + OPCODE(o2_setRenderFlags), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + OPCODE(o1_loadAnim), + OPCODE(o1_freeAnim), + OPCODE(o1_updateAnim), + OPCODE(o2_multSub), + /* 14 */ + OPCODE(o2_initMult), + OPCODE(o1_freeMult), + OPCODE(o1_animate), + OPCODE(o2_loadMultObject), + /* 18 */ + OPCODE(o1_getAnimLayerInfo), + OPCODE(o1_getObjAnimSize), + OPCODE(o1_loadStatic), + OPCODE(o1_freeStatic), + /* 1C */ + OPCODE(o2_renderStatic), + OPCODE(o2_loadCurLayer), + {NULL, ""}, + {NULL, ""}, + /* 20 */ + OPCODE(o2_playCDTrack), + OPCODE(o2_waitCDTrackEnd), + OPCODE(o2_stopCD), + OPCODE(o2_readLIC), + /* 24 */ + OPCODE(o2_freeLIC), + OPCODE(o2_getCDTrackPos), + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o2_loadFontToSprite), + OPCODE(o1_freeFontToSprite), + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + OPCODE(o2_totSub), + OPCODE(o2_switchTotSub), + OPCODE(o2_copyVars), + OPCODE(o2_pasteVars), + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 48 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 4C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 50 */ + OPCODE(o2_loadMapObjects), + OPCODE(o2_freeGoblins), + OPCODE(o2_moveGoblin), + OPCODE(o2_writeGoblinPos), + /* 54 */ + OPCODE(o2_stopGoblin), + OPCODE(o2_setGoblinState), + OPCODE(o2_placeGoblin), + {NULL, ""}, + /* 58 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 5C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 60 */ + {NULL, ""}, + OPCODE(o5_deleteFile), + {NULL, ""}, + {NULL, ""}, + /* 64 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 68 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 6C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 70 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 74 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 78 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 7C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 80 */ + OPCODE(o4_initScreen), + OPCODE(o2_scroll), + OPCODE(o2_setScrollOffset), + OPCODE(o4_playVmdOrMusic), + /* 84 */ + OPCODE(o2_getImdInfo), + OPCODE(o2_openItk), + OPCODE(o2_closeItk), + OPCODE(o2_setImdFrontSurf), + /* 88 */ + OPCODE(o2_resetImdFrontSurf), + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 8C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 90 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 94 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 98 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 9C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* AC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* BC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* CC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* DC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* EC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* FC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""} + }; + + static const OpcodeFuncEntryV5 opcodesFunc[80] = { + /* 00 */ + OPCODE(o1_callSub), + OPCODE(o1_callSub), + OPCODE(o1_printTotText), + OPCODE(o1_loadCursor), + /* 04 */ + {NULL, ""}, + OPCODE(o1_switch), + OPCODE(o1_repeatUntil), + OPCODE(o1_whileDo), + /* 08 */ + OPCODE(o1_if), + OPCODE(o2_evaluateStore), + OPCODE(o1_loadSpriteToPos), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + OPCODE(o2_printText), + OPCODE(o1_loadTot), + OPCODE(o1_palLoad), + /* 14 */ + OPCODE(o1_keyFunc), + OPCODE(o1_capturePush), + OPCODE(o1_capturePop), + OPCODE(o2_animPalInit), + /* 18 */ + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), + OPCODE(o3_getTotTextItemPart), + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_drawOperations), + OPCODE(o1_setcmdCount), + /* 20 */ + OPCODE(o1_return), + OPCODE(o1_renewTimeInVars), + OPCODE(o1_speakerOn), + OPCODE(o1_speakerOff), + /* 24 */ + OPCODE(o1_putPixel), + OPCODE(o2_goblinFunc), + OPCODE(o2_createSprite), + OPCODE(o1_freeSprite), + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o1_returnTo), + OPCODE(o1_loadSpriteContent), + OPCODE(o1_copySprite), + OPCODE(o1_fillRect), + /* 34 */ + OPCODE(o1_drawLine), + OPCODE(o1_strToLong), + OPCODE(o1_invalidate), + OPCODE(o1_setBackDelta), + /* 38 */ + OPCODE(o1_playSound), + OPCODE(o2_stopSound), + OPCODE(o2_loadSound), + OPCODE(o1_freeSoundSlot), + /* 3C */ + OPCODE(o1_waitEndPlay), + OPCODE(o1_playComposition), + OPCODE(o2_getFreeMem), + OPCODE(o2_checkData), + /* 40 */ + {NULL, ""}, + OPCODE(o1_prepareStr), + OPCODE(o1_insertStr), + OPCODE(o1_cutStr), + /* 44 */ + OPCODE(o1_strstr), + OPCODE(o5_istrlen), + OPCODE(o1_setMousePos), + OPCODE(o1_setFrameRate), + /* 48 */ + OPCODE(o1_animatePalette), + OPCODE(o1_animateCursor), + OPCODE(o1_blitCursor), + OPCODE(o1_loadFont), + /* 4C */ + OPCODE(o1_freeFont), + OPCODE(o2_readData), + OPCODE(o2_writeData), + OPCODE(o1_manageDataFile), + }; + + static const OpcodeGoblinEntryV5 opcodesGoblin[71] = { + /* 00 */ + OPCODE(o5_spaceShooter), + OPCODE(o5_getSystemCDSpeed), + OPCODE(o5_getSystemRAM), + OPCODE(o5_getSystemCPUSpeed), + /* 04 */ + OPCODE(o5_getSystemDrawSpeed), + OPCODE(o5_totalSystemSpecs), + OPCODE(o5_saveSystemSpecs), + OPCODE(o5_loadSystemSpecs), + /* 08 */ + OPCODE(o5_gob92), + OPCODE(o5_gob95), + OPCODE(o5_gob96), + OPCODE(o5_gob97), + /* 0C */ + OPCODE(o5_gob98), + OPCODE(o5_gob100), + OPCODE(o5_gob200), + {NULL, ""}, + /* 10 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 14 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 18 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 20 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 24 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + }; + + _opcodesDrawV5 = opcodesDraw; + _opcodesFuncV5 = opcodesFunc; + _opcodesGoblinV5 = opcodesGoblin; +} + +void Inter_v5::executeDrawOpcode(byte i) { + debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", + i, i, getOpcodeDrawDesc(i)); + + OpcodeDrawProcV5 op = _opcodesDrawV5[i].proc; + + if (op == NULL) + warning("unimplemented opcodeDraw: %d", i); + else + (this->*op) (); +} + +bool Inter_v5::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { + debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", + i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); + + if ((i > 4) || (j > 15)) { + warning("unimplemented opcodeFunc: %d.%d", i, j); + return false; + } + + OpcodeFuncProcV5 op = _opcodesFuncV5[i*16 + j].proc; + + if (op == NULL) + warning("unimplemented opcodeFunc: %d.%d", i, j); + else + return (this->*op) (params); + + return false; +} + +void Inter_v5::executeGoblinOpcode(int i, OpGobParams ¶ms) { + debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", + i, i, getOpcodeGoblinDesc(i)); + + OpcodeGoblinProcV5 op = NULL; + + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) { + op = _opcodesGoblinV5[_goblinFuncLookUp[j][1]].proc; + break; + } + + _vm->_global->_inter_execPtr -= 2; + + if (op == NULL) { + warning("unimplemented opcodeGoblin: %d", i); + + int16 paramCount = load16(); + _vm->_global->_inter_execPtr += paramCount * 2; + } else { + params.extraData = i; + + (this->*op) (params); + } +} + +const char *Inter_v5::getOpcodeDrawDesc(byte i) { + return _opcodesDrawV5[i].desc; +} + +const char *Inter_v5::getOpcodeFuncDesc(byte i, byte j) { + if ((i > 4) || (j > 15)) + return ""; + + return _opcodesFuncV5[i*16 + j].desc; +} + +const char *Inter_v5::getOpcodeGoblinDesc(int i) { + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) + return _opcodesGoblinV5[_goblinFuncLookUp[j][1]].desc; + return ""; +} + +void Inter_v5::o5_deleteFile() { + evalExpr(0); + + warning("Dynasty Stub: deleteFile \"%s\"", _vm->_global->_inter_resStr); +} + +bool Inter_v5::o5_istrlen(OpFuncParams ¶ms) { + int16 strVar1, strVar2; + int16 len; + + if (*_vm->_global->_inter_execPtr == 0x80) { + _vm->_global->_inter_execPtr++; + + strVar1 = _vm->_parse->parseVarIndex(); + strVar2 = _vm->_parse->parseVarIndex(); + + len = _vm->_draw->stringLength(GET_VARO_STR(strVar1), READ_VARO_UINT16(strVar2)); + + } else { + + strVar1 = _vm->_parse->parseVarIndex(); + strVar2 = _vm->_parse->parseVarIndex(); + + if (_vm->_global->_language == 10) { + // Extra handling for Japanese strings + + for (len = 0; READ_VARO_UINT8(strVar1) != 0; strVar1++, len++) + if (READ_VARO_UINT8(strVar1) >= 128) + strVar1++; + + } else + len = strlen(GET_VARO_STR(strVar1)); + } + + WRITE_VAR_OFFSET(strVar2, len); + return false; +} + +void Inter_v5::o5_spaceShooter(OpGobParams ¶ms) { + int16 paramCount = load16(); + + warning("Dynasty Stub: Space shooter: %d, %d, %s", + params.extraData, paramCount, _vm->_game->_curTotFile); + + if (paramCount < 4) { + warning("Space shooter variable counter < 4"); + _vm->_global->_inter_execPtr += paramCount * 2; + return; + } + + uint32 var1 = load16() * 4; + uint32 var2 = load16() * 4; +#if 1 + load16(); + load16(); +#else + uint32 var3 = load16() * 4; + uint16 var4 = load16(); +#endif + + if (params.extraData != 0) { + WRITE_VARO_UINT32(var1, 0); + WRITE_VARO_UINT32(var2, 0); + } else { + if (paramCount < 5) { + warning("Space shooter variable counter < 5"); + return; + } + + _vm->_global->_inter_execPtr += (paramCount - 4) * 2; + } +} + +void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + + Video::FontDesc *font; + if ((font = _vm->_util->loadFont("SPEED.LET"))) { + _vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, _vm->_draw->_backSurface, font); + _vm->_draw->forceBlit(); + + _vm->_util->freeFont(font); + } +} + +void Inter_v5::o5_saveSystemSpecs(OpGobParams ¶ms) { + warning("Dynasty Stub: Saving system specifications"); + + _vm->_global->_inter_execPtr += 2; + +/* + FILE *f = fopen("SAVE\\SPEED.INF", w); + fwrite(&_cdSpeed, sizeof(_cdSpeed), 1, f); + fwrite(&_ram, sizeof(_ram), 1, f); + fwrite(&_cpuSpeed, sizeof(_cpuSpeed), 1, f); + fwrite(&_drawSpeed, sizeof(_drawSpeed), 1, f); + fwrite(&_total, sizeof(_total), 1, f); + fclose(f); +*/ +} + +void Inter_v5::o5_loadSystemSpecs(OpGobParams ¶ms) { + warning("Dynasty Stub: Loading system specifications"); + + _vm->_global->_inter_execPtr += 2; + +/* + FILE *f = fopen("SAVE\\SPEED.INF", r); + fread(&_cdSpeed, sizeof(_cdSpeed), 1, f); + fread(&_ram, sizeof(_ram), 1, f); + fread(&_cpuSpeed, sizeof(_cpuSpeed), 1, f); + fread(&_drawSpeed, sizeof(_drawSpeed), 1, f); + fread(&_total, sizeof(_total), 1, f); + fclose(f); +*/ + +/* + // Calculating whether speed throttling is necessary? + + var_E = MAX(_cdSpeed, 150); + var_E += (_ram << 3); + var_E += (_cpuSpeed << 3); + var_E /= 17; + + byte_8A61E = (var_E > 81) ? 1 : 0; + byte_8A5E0 = (_total >= 95) ? 1 : 0; + + if (byte_8A5E0 == 1) { + word_8AEE2 = 100; + byte_8AEE4 = 1; + byte_8AEE5 = 1; + word_8AEE6 = 0; + } else { + word_8AEE2 = 0; + byte_8AEE4 = 0; + byte_8AEE5 = 0; + word_8AEE6 = 40; + } +*/ +} + +void Inter_v5::o5_gob92(OpGobParams ¶ms) { + warning("Dynasty Stub: GobFunc 92"); + + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_86B9E)) */); +} + +void Inter_v5::o5_gob95(OpGobParams ¶ms) { + warning("Dynasty Stub: GobFunc 95"); + + _vm->_global->_inter_execPtr += 2; + + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE6)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE5)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE4)) */); + WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE2)) */); +} + +void Inter_v5::o5_gob96(OpGobParams ¶ms) { + int16 word_8AEE6, word_85B50, word_8AEE2; + byte byte_8AEE5, byte_8AEE4; + + _vm->_global->_inter_execPtr += 2; + + word_8AEE6 = word_85B50 = READ_VAR_UINT16(load16()); + byte_8AEE5 = READ_VAR_UINT8(load16()); + byte_8AEE4 = READ_VAR_UINT8(load16()); + word_8AEE2 = READ_VAR_UINT16(load16()); + + warning("Dynasty Stub: GobFunc 96: %d, %d, %d, %d", + word_8AEE6, byte_8AEE5, byte_8AEE4, word_8AEE2); + + // .--- sub_194B0 --- + + int16 word_8A8F0, word_8A8F2, word_8A8F4, word_8A8F6, word_8A8F8, word_8A8FA; + + int16 word_8A62C = 1; + int16 word_8A63C, word_8A640, word_8B464, word_8B466; + + byte byte_8A62E; + + int16 var_2, var_4; + + var_2 = word_85B50 + 31; + word_8A8F0 = word_8A8F2 = var_2; + word_8A8F4 = word_85B50; + + var_4 = 315 - word_85B50; + word_8A8F6 = word_8A8F8 = var_4; + + word_8A8FA = 479 - word_85B50; + + if (word_8A62C == 0) { + word_8A63C = word_8A8F0; + word_8A640 = word_8A8F6; + word_8B464 = word_8A8F0; + word_8B466 = word_8A8F6; + } else if (word_8A62C == 1) { + word_8A63C = word_85B50; + word_8A640 = word_8A8FA; + word_8B464 = word_85B50; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 2) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 3) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } else if (word_8A62C == 4) { + word_8A63C = word_8A8F4; + word_8A640 = word_8A8FA; + word_8B464 = word_8A8F4; + word_8B466 = word_8A8FA; + } + + byte_8A62E = 1; + +// '--- --- + +} + +void Inter_v5::o5_gob97(OpGobParams ¶ms) { + _byte_8AA14 = 1; + + _vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob98(OpGobParams ¶ms) { + _byte_8AA14 = 0; + + _vm->_global->_inter_execPtr += 2; +} + +void Inter_v5::o5_gob100(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + uint16 var1 = READ_VAR_UINT16(load16()); + uint16 var2 = READ_VAR_UINT16(load16()); + uint16 var3 = READ_VAR_UINT16(load16()); + uint16 var4 = READ_VAR_UINT16(load16()); + + warning("Dynasty Stub: GobFunc 100: %d, %d, %d, %d", var1, var2, var3, var4); + + var3 = (var3 + var1) - 1; + var4 = (var4 + var2) - 1; +} + +void Inter_v5::o5_gob200(OpGobParams ¶ms) { + _vm->_global->_inter_execPtr += 2; + + uint16 var1 = load16(); // index into the spritesArray + uint16 var2 = load16(); + uint16 var3 = load16(); + + warning("Dynasty Stub: GobFunc 200: %d, %d, %d", var1, var2, var3); +} + +} // End of namespace Gob diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp new file mode 100644 index 0000000000..d27bcc64b5 --- /dev/null +++ b/engines/gob/inter_v6.cpp @@ -0,0 +1,866 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" +#include "common/file.h" + +#include "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/draw.h" + +namespace Gob { + +#define OPCODE(x) _OPCODE(Inter_v6, x) + +const int Inter_v6::_goblinFuncLookUp[][2] = { + {0, 0}, + {1, 0}, + {80, 1}, + {81, 2}, + {82, 3}, + {83, 4}, + {84, 5}, + {85, 6}, + {86, 7}, + {87, 0}, + {88, 0}, + {89, 0}, + {90, 0}, + {91, 0}, + {92, 8}, + {93, 0}, + {94, 0}, + {95, 9}, + {96, 10}, + {97, 11}, + {98, 12}, + {99, 0}, + {100, 13}, + {200, 14}, + {30, 24}, + {32, 25}, + {33, 26}, + {34, 27}, + {35, 28}, + {36, 29}, + {37, 30}, + {40, 31}, + {41, 32}, + {42, 33}, + {43, 34}, + {44, 35}, + {50, 36}, + {52, 37}, + {53, 38}, + {100, 39}, + {152, 40}, + {200, 41}, + {201, 42}, + {202, 43}, + {203, 44}, + {204, 45}, + {250, 46}, + {251, 47}, + {252, 48}, + {500, 49}, + {502, 50}, + {503, 51}, + {600, 52}, + {601, 53}, + {602, 54}, + {603, 55}, + {604, 56}, + {605, 57}, + {1000, 58}, + {1001, 59}, + {1002, 60}, + {1003, 61}, + {1004, 62}, + {1005, 63}, + {1006, 64}, + {1008, 65}, + {1009, 66}, + {1010, 67}, + {1011, 68}, + {1015, 69}, + {2005, 70} +}; + +Inter_v6::Inter_v6(GobEngine *vm) : Inter_v5(vm) { + setupOpcodes(); +} + +void Inter_v6::setupOpcodes() { + static const OpcodeDrawEntryV6 opcodesDraw[256] = { + /* 00 */ + OPCODE(o1_loadMult), + OPCODE(o2_playMult), + OPCODE(o2_freeMultKeys), + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_initCursor), + /* 08 */ + OPCODE(o1_initCursorAnim), + OPCODE(o1_clearCursorAnim), + OPCODE(o2_setRenderFlags), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + OPCODE(o1_loadAnim), + OPCODE(o1_freeAnim), + OPCODE(o1_updateAnim), + OPCODE(o2_multSub), + /* 14 */ + OPCODE(o2_initMult), + OPCODE(o1_freeMult), + OPCODE(o1_animate), + OPCODE(o2_loadMultObject), + /* 18 */ + OPCODE(o1_getAnimLayerInfo), + OPCODE(o1_getObjAnimSize), + OPCODE(o1_loadStatic), + OPCODE(o1_freeStatic), + /* 1C */ + OPCODE(o2_renderStatic), + OPCODE(o2_loadCurLayer), + {NULL, ""}, + {NULL, ""}, + /* 20 */ + OPCODE(o2_playCDTrack), + OPCODE(o2_waitCDTrackEnd), + OPCODE(o2_stopCD), + OPCODE(o2_readLIC), + /* 24 */ + OPCODE(o2_freeLIC), + OPCODE(o2_getCDTrackPos), + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o2_loadFontToSprite), + OPCODE(o1_freeFontToSprite), + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + OPCODE(o2_totSub), + OPCODE(o2_switchTotSub), + OPCODE(o2_copyVars), + OPCODE(o2_pasteVars), + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 48 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 4C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 50 */ + OPCODE(o2_loadMapObjects), + OPCODE(o2_freeGoblins), + OPCODE(o2_moveGoblin), + OPCODE(o2_writeGoblinPos), + /* 54 */ + OPCODE(o2_stopGoblin), + OPCODE(o2_setGoblinState), + OPCODE(o2_placeGoblin), + {NULL, ""}, + /* 58 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 5C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 60 */ + {NULL, ""}, + OPCODE(o5_deleteFile), + {NULL, ""}, + {NULL, ""}, + /* 64 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 68 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 6C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 70 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 74 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 78 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 7C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 80 */ + OPCODE(o4_initScreen), + OPCODE(o2_scroll), + OPCODE(o2_setScrollOffset), + OPCODE(o4_playVmdOrMusic), + /* 84 */ + OPCODE(o2_getImdInfo), + OPCODE(o2_openItk), + OPCODE(o2_closeItk), + OPCODE(o2_setImdFrontSurf), + /* 88 */ + OPCODE(o2_resetImdFrontSurf), + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 8C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 90 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 94 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 98 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 9C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* AC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* BC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* CC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* DC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* EC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* FC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""} + }; + + static const OpcodeFuncEntryV6 opcodesFunc[80] = { + /* 00 */ + OPCODE(o1_callSub), + OPCODE(o1_callSub), + OPCODE(o1_printTotText), + OPCODE(o6_loadCursor), + /* 04 */ + {NULL, ""}, + OPCODE(o1_switch), + OPCODE(o1_repeatUntil), + OPCODE(o1_whileDo), + /* 08 */ + OPCODE(o1_if), + OPCODE(o6_evaluateStore), + OPCODE(o1_loadSpriteToPos), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + OPCODE(o2_printText), + OPCODE(o1_loadTot), + OPCODE(o1_palLoad), + /* 14 */ + OPCODE(o1_keyFunc), + OPCODE(o1_capturePush), + OPCODE(o1_capturePop), + OPCODE(o2_animPalInit), + /* 18 */ + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), + OPCODE(o3_getTotTextItemPart), + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_drawOperations), + OPCODE(o1_setcmdCount), + /* 20 */ + OPCODE(o1_return), + OPCODE(o1_renewTimeInVars), + OPCODE(o1_speakerOn), + OPCODE(o1_speakerOff), + /* 24 */ + OPCODE(o1_putPixel), + OPCODE(o2_goblinFunc), + OPCODE(o2_createSprite), + OPCODE(o1_freeSprite), + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o1_returnTo), + OPCODE(o1_loadSpriteContent), + OPCODE(o1_copySprite), + OPCODE(o1_fillRect), + /* 34 */ + OPCODE(o1_drawLine), + OPCODE(o1_strToLong), + OPCODE(o1_invalidate), + OPCODE(o1_setBackDelta), + /* 38 */ + OPCODE(o1_playSound), + OPCODE(o2_stopSound), + OPCODE(o2_loadSound), + OPCODE(o1_freeSoundSlot), + /* 3C */ + OPCODE(o1_waitEndPlay), + OPCODE(o1_playComposition), + OPCODE(o2_getFreeMem), + OPCODE(o2_checkData), + /* 40 */ + {NULL, ""}, + OPCODE(o1_prepareStr), + OPCODE(o1_insertStr), + OPCODE(o1_cutStr), + /* 44 */ + OPCODE(o1_strstr), + OPCODE(o5_istrlen), + OPCODE(o1_setMousePos), + OPCODE(o1_setFrameRate), + /* 48 */ + OPCODE(o1_animatePalette), + OPCODE(o1_animateCursor), + OPCODE(o1_blitCursor), + OPCODE(o1_loadFont), + /* 4C */ + OPCODE(o1_freeFont), + OPCODE(o2_readData), + OPCODE(o2_writeData), + OPCODE(o1_manageDataFile), + }; + + static const OpcodeGoblinEntryV6 opcodesGoblin[71] = { + /* 00 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 08 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 14 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 18 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 20 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 24 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + }; + + _opcodesDrawV6 = opcodesDraw; + _opcodesFuncV6 = opcodesFunc; + _opcodesGoblinV6 = opcodesGoblin; +} + +void Inter_v6::executeDrawOpcode(byte i) { + debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", + i, i, getOpcodeDrawDesc(i)); + + OpcodeDrawProcV6 op = _opcodesDrawV6[i].proc; + + if (op == NULL) + warning("unimplemented opcodeDraw: %d", i); + else + (this->*op) (); +} + +bool Inter_v6::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { + debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", + i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); + + if ((i > 4) || (j > 15)) { + warning("unimplemented opcodeFunc: %d.%d", i, j); + return false; + } + + OpcodeFuncProcV6 op = _opcodesFuncV6[i*16 + j].proc; + + if (op == NULL) + warning("unimplemented opcodeFunc: %d.%d", i, j); + else + return (this->*op) (params); + + return false; +} + +void Inter_v6::executeGoblinOpcode(int i, OpGobParams ¶ms) { + debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", + i, i, getOpcodeGoblinDesc(i)); + + OpcodeGoblinProcV6 op = NULL; + + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) { + op = _opcodesGoblinV6[_goblinFuncLookUp[j][1]].proc; + break; + } + + _vm->_global->_inter_execPtr -= 2; + + if (op == NULL) { + warning("unimplemented opcodeGoblin: %d", i); + + int16 paramCount = load16(); + _vm->_global->_inter_execPtr += paramCount * 2; + } else { + params.extraData = i; + + (this->*op) (params); + } +} + +const char *Inter_v6::getOpcodeDrawDesc(byte i) { + return _opcodesDrawV6[i].desc; +} + +const char *Inter_v6::getOpcodeFuncDesc(byte i, byte j) { + if ((i > 4) || (j > 15)) + return ""; + + return _opcodesFuncV6[i*16 + j].desc; +} + +const char *Inter_v6::getOpcodeGoblinDesc(int i) { + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) + return _opcodesGoblinV6[_goblinFuncLookUp[j][1]].desc; + return ""; +} + +bool Inter_v6::o6_loadCursor(OpFuncParams ¶ms) { + Game::TotResItem *itemPtr; + int16 width, height; + byte *dataBuf; + int32 offset; + int16 id; + int8 index; + + id = load16(); + + if (id == -1) { + byte str[10]; + + for (int i = 0; i < 9; i++) + str[i] = *_vm->_global->_inter_execPtr++; + + str[9] = '\0'; + + uint16 var1 = load16(); + int8 var2 = *_vm->_global->_inter_execPtr++; + + warning("Urban Stub: loadCursor %d: \"%s\", %d, %d", id, str, var1, var2); + + } else if (id == -2) { + + uint16 var1 = load16(); + uint16 var2 = load16(); + int8 var3 = *_vm->_global->_inter_execPtr++; + + warning("Urban Stub: loadCursor %d: %d, %d, %d", id, var1, var2, var3); + + } else { + index = (int8) *_vm->_global->_inter_execPtr++; + + if ((index * _vm->_draw->_cursorWidth) >= _vm->_draw->_cursorSprites->getWidth()) + return false; + + itemPtr = &_vm->_game->_totResourceTable->items[id]; + offset = itemPtr->offset; + + if (offset < 0) { + offset = (-offset - 1) * 4; + dataBuf = _vm->_game->_imFileData + + (int32) READ_LE_UINT32(_vm->_game->_imFileData + offset); + } else + dataBuf = _vm->_game->_totResourceTable->dataPtr + szGame_TotResTable + + szGame_TotResItem * _vm->_game->_totResourceTable->itemsCount + + offset; + + width = itemPtr->width; + height = itemPtr->height; + + _vm->_video->fillRect(_vm->_draw->_cursorSprites, + index * _vm->_draw->_cursorWidth, 0, + index * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1, + _vm->_draw->_cursorHeight - 1, 0); + + _vm->_video->drawPackedSprite(dataBuf, width, height, + index * _vm->_draw->_cursorWidth, 0, 0, _vm->_draw->_cursorSprites); + _vm->_draw->_cursorAnimLow[index] = 0; + } + + return false; +} + +bool Inter_v6::o6_evaluateStore(OpFuncParams ¶ms) { + byte *savedPos; + int16 varOff; + int16 token; + int16 result; + byte loopCount; + uint16 var_6, var_A; + + varOff = _vm->_parse->parseVarIndex(&var_6, &var_A); + + if (var_6 != 0) { + int16 var_4; + + savedPos = _vm->_global->_inter_execPtr; + + var_4 = _vm->_parse->parseVarIndex(&var_6, 0); + + memcpy(_vm->_inter->_variables->getAddressOff8(varOff), + _vm->_inter->_variables->getAddressOff8(var_4), var_6 * 4); + + _vm->_global->_inter_execPtr = savedPos; + evalExpr(&var_4); + + return false; + } + + if (*_vm->_global->_inter_execPtr == 98) { + _vm->_global->_inter_execPtr++; + loopCount = *_vm->_global->_inter_execPtr++; + + for (int i = 0; i < loopCount; i++) { + uint8 c = *_vm->_global->_inter_execPtr++; + uint16 n = load16(); + + memset(_vm->_inter->_variables->getAddressOff8(varOff), c, n); + + varOff += n; + } + + return false; + + } else if (*_vm->_global->_inter_execPtr == 99) { + _vm->_global->_inter_execPtr++; + loopCount = *_vm->_global->_inter_execPtr++; + } else + loopCount = 1; + + for (int i = 0; i < loopCount; i++) { + token = evalExpr(&result); + switch (var_A) { + case 16: + case 18: + WRITE_VARO_UINT8(varOff + i, _vm->_global->_inter_resVal); + break; + + case 17: + case 27: + WRITE_VARO_UINT16(varOff + i * 2, _vm->_global->_inter_resVal); + break; + + case 23: + case 26: + WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal); + break; + + case 24: + WRITE_VARO_UINT16(varOff + i * 4, _vm->_global->_inter_resVal); + break; + + case 25: + case 28: + if (token == 20) + WRITE_VARO_UINT8(varOff, result); + else + WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr); + break; + } + } + + return false; +} + +} // End of namespace Gob diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index 75867aaa6c..bb259800c0 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -77,10 +77,10 @@ Map::~Map() { } void Map::placeItem(int16 x, int16 y, int16 id) { - if ((_itemsMap[y][x] & 0xFF00) != 0) - _itemsMap[y][x] = (_itemsMap[y][x] & 0xFF00) | id; + if ((getItem(x, y) & 0xFF00) != 0) + setItem(x, y, (getItem(x, y) & 0xFF00) | id); else - _itemsMap[y][x] = (_itemsMap[y][x] & 0x00FF) | (id << 8); + setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8)); } enum { diff --git a/engines/gob/map.h b/engines/gob/map.h index 8a94de8da9..4a211f205d 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -101,6 +101,9 @@ public: void loadMapsInitGobs(void); + virtual int16 getItem(int x, int y) = 0; + virtual void setItem(int x, int y, int16 item) = 0; + virtual int8 getPass(int x, int y, int heightOff = -1) = 0; virtual void setPass(int x, int y, int8 pass, int heightOff = -1) = 0; @@ -127,6 +130,23 @@ public: virtual void findNearestToDest(Mult::Mult_Object *obj); virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y); + virtual int16 getItem(int x, int y) { + assert(_itemsMap); + + x = CLIP<int>(x, 0, _mapWidth - 1); + y = CLIP<int>(y, 0, _mapHeight - 1); + + return _itemsMap[y][x]; + } + virtual void setItem(int x, int y, int16 item) { + assert(_itemsMap); + + x = CLIP<int>(x, 0, _mapWidth - 1); + y = CLIP<int>(y, 0, _mapHeight - 1); + + _itemsMap[y][x] = item; + } + virtual int8 getPass(int x, int y, int heightOff = -1) { if (!_passMap) return 0; diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 45048a0899..3ec542934f 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -30,6 +30,8 @@ MODULE_OBJS := \ inter_bargon.o \ inter_v3.o \ inter_v4.o \ + inter_v5.o \ + inter_v6.o \ map.o \ map_v1.o \ map_v2.o \ @@ -53,6 +55,7 @@ MODULE_OBJS := \ video.o \ video_v1.o \ video_v2.o \ + video_v6.o \ sound/sound.o \ sound/sounddesc.o \ sound/pcspeaker.o \ diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index b9373d48b3..a502e92188 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -209,7 +209,7 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, _frame++; _vm->_util->waitEndFrame(); - } while (!stop && !stopNoClear && !_vm->_quitRequested); + } while (!stop && !stopNoClear && !_vm->quit()); if (!stopNoClear) { if (_animDataAllocated) { diff --git a/engines/gob/palanim.cpp b/engines/gob/palanim.cpp index 71e73adf53..4f2e921dcb 100644 --- a/engines/gob/palanim.cpp +++ b/engines/gob/palanim.cpp @@ -23,6 +23,7 @@ * */ + #include "gob/gob.h" #include "gob/palanim.h" #include "gob/global.h" @@ -131,7 +132,7 @@ void PalAnim::fade(Video::PalDesc *palDesc, int16 fadeV, int16 allColors) { bool stop; int16 i; - if (_vm->_quitRequested) + if (_vm->quit()) return; _fadeValue = (fadeV < 0) ? -fadeV : 2; diff --git a/engines/gob/parse.h b/engines/gob/parse.h index 7d451b5f79..15ec78b57f 100644 --- a/engines/gob/parse.h +++ b/engines/gob/parse.h @@ -33,7 +33,7 @@ public: void skipExpr(char stopToken); void printExpr(char stopToken); void printVarIndex(void); - virtual int16 parseVarIndex(void) = 0; + virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0) = 0; virtual int16 parseValExpr(byte stopToken = 99) = 0; virtual int16 parseExpr(byte stopToken, byte *resultPtr) = 0; @@ -60,7 +60,7 @@ public: Parse_v1(GobEngine *vm); virtual ~Parse_v1() {} - virtual int16 parseVarIndex(void); + virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0); virtual int16 parseValExpr(byte stopToken = 99); virtual int16 parseExpr(byte stopToken, byte *resultPtr); }; @@ -70,7 +70,7 @@ public: Parse_v2(GobEngine *vm); virtual ~Parse_v2() {} - virtual int16 parseVarIndex(void); + virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0); virtual int16 parseValExpr(byte stopToken = 99); virtual int16 parseExpr(byte stopToken, byte *resultPtr); }; diff --git a/engines/gob/parse_v1.cpp b/engines/gob/parse_v1.cpp index 3c5f90c068..ed8868397a 100644 --- a/engines/gob/parse_v1.cpp +++ b/engines/gob/parse_v1.cpp @@ -35,7 +35,7 @@ namespace Gob { Parse_v1::Parse_v1(GobEngine *vm) : Parse(vm) { } -int16 Parse_v1::parseVarIndex() { +int16 Parse_v1::parseVarIndex(uint16 *arg_0, uint16 *arg_4) { int16 temp2; byte *arrDesc; int16 dim; diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp index a2e6b8fb37..347a253204 100644 --- a/engines/gob/parse_v2.cpp +++ b/engines/gob/parse_v2.cpp @@ -35,7 +35,7 @@ namespace Gob { Parse_v2::Parse_v2(GobEngine *vm) : Parse_v1(vm) { } -int16 Parse_v2::parseVarIndex() { +int16 Parse_v2::parseVarIndex(uint16 *arg_0, uint16 *arg_4) { int16 temp2; byte *arrDesc; int16 dim; @@ -44,8 +44,74 @@ int16 Parse_v2::parseVarIndex() { int16 temp; int16 offset; int16 val; + uint32 varPos = 0; operation = *_vm->_global->_inter_execPtr++; + + while ((operation == 14) || (operation == 15)) { + if (operation == 14) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + if (arg_0) + *arg_0 = READ_LE_UINT16(_vm->_global->_inter_execPtr); + if (arg_4) + *arg_4 = 14; + + _vm->_global->_inter_execPtr += 2; + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } else if (operation == 15) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + uint16 var_0C = _vm->_inter->load16(); + if (arg_0) + *arg_0 = var_0C; + if (arg_4) + *arg_4 = 15; + + uint8 var_A = *_vm->_global->_inter_execPtr++; + + byte *var_12 = _vm->_global->_inter_execPtr; + _vm->_global->_inter_execPtr += var_A; + + uint16 var_6 = 0; + + for (int i = 0; i < var_A; i++) { + temp2 = parseValExpr(12); + + //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + + uint16 ax; + + if (temp2 < 0) { + ax = 0; + } else if (var_12[i] > temp2) { + ax = temp2; + } else { + ax = var_12[i] - 1; + } + + var_6 = var_6 * var_12[i] + ax; + } + + varPos += var_6 * var_0C * 4; + + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } + + warning("v5+ Stub: parseVarIndex operation %d, offset %d", operation, varPos); + + operation = *_vm->_global->_inter_execPtr++; + } + + if (arg_0) + *arg_0 = 0; + if (arg_4) + *arg_4 = operation; + debugC(5, kDebugParser, "var parse = %d", operation); switch (operation) { case 16: @@ -62,24 +128,24 @@ int16 Parse_v2::parseVarIndex() { offset = arrDesc[dim] * offset + temp2; } if (operation == 16) - return temp + offset; + return varPos + temp + offset; if (operation == 26) - return (temp + offset) * 4; + return varPos + (temp + offset) * 4; if (operation == 27) - return (temp + offset) * 2; + return varPos + (temp + offset) * 2; temp *= 4; offset *= 4; if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; temp += parseValExpr(12); } - return offset * _vm->_global->_inter_animDataSize + temp; + return varPos + offset * _vm->_global->_inter_animDataSize + temp; case 17: - return _vm->_inter->load16() * 2; + return varPos + _vm->_inter->load16() * 2; case 18: - return _vm->_inter->load16(); + return varPos + _vm->_inter->load16(); case 23: case 24: @@ -93,7 +159,7 @@ int16 Parse_v2::parseVarIndex() { temp += val; debugC(5, kDebugParser, "parse subscript = %d", val); } - return temp; + return varPos + temp; default: return 0; @@ -116,6 +182,7 @@ int16 Parse_v2::parseValExpr(byte stopToken) { int16 brackPos; static int16 flag = 0; int16 oldflag; + uint32 varPos = 0; memset(values, 0, 20 * sizeof(int16)); @@ -130,11 +197,61 @@ int16 Parse_v2::parseValExpr(byte stopToken) { valPtr = values - 1; while (1) { + operation = *_vm->_global->_inter_execPtr++; + + while ((operation == 14) || (operation == 15)) { + if (operation == 14) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + _vm->_global->_inter_execPtr += 2; + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } else if (operation == 15) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + uint16 var_0C = _vm->_inter->load16(); + uint8 var_A = *_vm->_global->_inter_execPtr++; + + byte *var_12 = _vm->_global->_inter_execPtr; + _vm->_global->_inter_execPtr += var_A; + + uint16 var_6 = 0; + + for (int i = 0; i < var_A; i++) { + temp2 = parseValExpr(12); + + //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + + uint16 ax; + + if (temp2 < 0) { + ax = 0; + } else if (var_12[i] > temp2) { + ax = temp2; + } else { + ax = var_12[i] - 1; + } + + var_6 = var_6 * var_12[i] + ax; + } + + varPos += var_6 * var_0C * 4; + + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } + + warning("v5+ Stub: parseValExpr operation %d, offset %d", operation, varPos); + + operation = *_vm->_global->_inter_execPtr++; + } + stkPos++; operPtr++; valPtr++; - operation = *_vm->_global->_inter_execPtr++; if ((operation >= 16) && (operation <= 29)) { *operPtr = 20; switch (operation) { @@ -152,29 +269,29 @@ int16 Parse_v2::parseValExpr(byte stopToken) { offset = arrDesc[dim] * offset + temp2; } if (operation == 16) - *valPtr = (int8) READ_VARO_UINT8(temp + offset); + *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset); else if (operation == 26) - *valPtr = (uint16) READ_VARO_UINT32(temp * 4 + offset * 4); + *valPtr = (uint16) READ_VARO_UINT32(varPos + temp * 4 + offset * 4); else if (operation == 27) - *valPtr = READ_VARO_UINT16(temp * 2 + offset * 2); + *valPtr = READ_VARO_UINT16(varPos + temp * 2 + offset * 2); else if (operation == 28) { _vm->_global->_inter_execPtr++; temp2 = parseValExpr(12); - *valPtr = READ_VARO_UINT8(temp * 4 + + *valPtr = READ_VARO_UINT8(varPos + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2); } break; case 17: - *valPtr = READ_VARO_UINT16(_vm->_inter->load16() * 2); + *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2); break; case 18: - *valPtr = (int8) READ_VARO_UINT8(_vm->_inter->load16()); + *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16()); break; case 19: - *valPtr = (uint16) READ_LE_UINT32(_vm->_global->_inter_execPtr); + *valPtr = (uint16) READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr); _vm->_global->_inter_execPtr += 4; break; @@ -191,14 +308,14 @@ int16 Parse_v2::parseValExpr(byte stopToken) { break; case 24: - *valPtr = READ_VARO_UINT16(_vm->_inter->load16() * 4); + *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4); break; case 25: temp = _vm->_inter->load16() * 4; _vm->_global->_inter_execPtr++; temp += parseValExpr(12); - *valPtr = READ_VARO_UINT8(temp); + *valPtr = READ_VARO_UINT8(varPos + temp); break; case 29: @@ -373,6 +490,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { bool var_1A; int16 stkPos; int16 brackStart; + uint32 varPos = 0; memset(operStack, 0, 20); @@ -381,10 +499,61 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { valPtr = values - 1; while (1) { + operation = *_vm->_global->_inter_execPtr++; + + while ((operation == 14) || (operation == 15)) { + if (operation == 14) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + _vm->_global->_inter_execPtr += 2; + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } else if (operation == 15) { + uint16 n = _vm->_inter->load16(); + varPos += n * 4; + + uint16 var_0C = _vm->_inter->load16(); + uint8 var_A = *_vm->_global->_inter_execPtr++; + + byte *var_12 = _vm->_global->_inter_execPtr; + _vm->_global->_inter_execPtr += var_A; + + uint16 var_6 = 0; + + for (int i = 0; i < var_A; i++) { + temp2 = parseValExpr(12); + + //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0); + + uint16 ax; + + if (temp2 < 0) { + ax = 0; + } else if (var_12[i] > temp2) { + ax = temp2; + } else { + ax = var_12[i] - 1; + } + + var_6 = var_6 * var_12[i] + ax; + } + + varPos += var_6 * var_0C * 4; + + if (*_vm->_global->_inter_execPtr == 97) + _vm->_global->_inter_execPtr++; + } + + warning("v5+ Stub: parseExpr operation %d, offset %d", operation, varPos); + + operation = *_vm->_global->_inter_execPtr++; + } + stkPos++; operPtr++; valPtr++; - operation = *_vm->_global->_inter_execPtr++; + if ((operation >= 16) && (operation <= 29)) { switch (operation) { case 16: @@ -402,20 +571,20 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { offset = offset * arrDescPtr[dim] + temp2; } if (operation == 16) - *valPtr = (int8) READ_VARO_UINT8(temp + offset); + *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset); else if (operation == 26) - *valPtr = READ_VARO_UINT32(temp * 4 + offset * 4); + *valPtr = READ_VARO_UINT32(varPos + temp * 4 + offset * 4); else if (operation == 27) - *valPtr = (int16) READ_VARO_UINT16(temp * 2 + offset * 2); + *valPtr = (int16) READ_VARO_UINT16(varPos + temp * 2 + offset * 2); else if (operation == 28) { *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( - temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), + varPos + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; temp2 = parseValExpr(12); *operPtr = 20; - *valPtr = READ_VARO_UINT8(temp * 4 + + *valPtr = READ_VARO_UINT8(varPos + temp * 4 + offset * 4 * _vm->_global->_inter_animDataSize + temp2); } } @@ -423,17 +592,17 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { case 17: *operPtr = 20; - *valPtr = (int16) READ_VARO_UINT16(_vm->_inter->load16() * 2); + *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2); break; case 18: *operPtr = 20; - *valPtr = (int8) READ_VARO_UINT8(_vm->_inter->load16()); + *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16()); break; case 19: *operPtr = 20; - *valPtr = READ_LE_UINT32(_vm->_global->_inter_execPtr); + *valPtr = READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr); _vm->_global->_inter_execPtr += 4; break; @@ -461,18 +630,18 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { case 24: *operPtr = 20; - *valPtr = (int16) READ_VARO_UINT16(_vm->_inter->load16() * 4); + *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4); break; case 25: *operPtr = 22; temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp, 0), kInterVar); + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(varPos + temp, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; temp += parseValExpr(12); *operPtr = 20; - *valPtr = READ_VARO_UINT8(temp); + *valPtr = READ_VARO_UINT8(varPos + temp); } break; diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp index fa9f8ea7a9..e3212ac8ff 100644 --- a/engines/gob/saveload.cpp +++ b/engines/gob/saveload.cpp @@ -513,7 +513,7 @@ bool StagedSave::read() { return false; } - uint32 saveSize = getSize(); + int32 saveSize = getSize(); if (in->size() != saveSize) { warning("Wrong size (%d != %d)", in->size(), saveSize); return false; diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp index 2d2bf8e043..7b93003791 100644 --- a/engines/gob/sound/sound.cpp +++ b/engines/gob/sound/sound.cpp @@ -369,7 +369,7 @@ void Sound::blasterWaitEndPlay(bool interruptible, bool stopComp) { if (stopComp) _blaster->endComposition(); - while (_blaster->isPlaying() && !_vm->_quitRequested) { + while (_blaster->isPlaying() && !_vm->quit()) { if (interruptible && (_vm->_util->checkKey() == 0x11B)) { WRITE_VAR(57, (uint32) -1); return; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 4987426fe0..fcf19f03dd 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -23,7 +23,6 @@ * */ -#include "common/events.h" #include "gob/gob.h" #include "gob/util.h" @@ -72,7 +71,7 @@ void Util::longDelay(uint16 msecs) { _vm->_video->waitRetrace(); processInput(); delay(15); - } while (!_vm->_quitRequested && + } while (!_vm->quit() && ((g_system->getMillis() * _vm->_global->_speedFactor) < time)); } @@ -118,9 +117,6 @@ void Util::processInput(bool scroll) { break; case Common::EVENT_KEYUP: break; - case Common::EVENT_QUIT: - _vm->_quitRequested = true; - break; default: break; } @@ -238,7 +234,9 @@ void Util::getMouseState(int16 *pX, int16 *pY, int16 *pButtons) { } void Util::setMousePos(int16 x, int16 y) { - g_system->warpMouse(x + _vm->_video->_screenDeltaX, y + _vm->_video->_screenDeltaY); + x = CLIP<int>(x + _vm->_video->_screenDeltaX, 0, _vm->_width - 1); + y = CLIP<int>(y + _vm->_video->_screenDeltaY, 0, _vm->_height - 1); + g_system->warpMouse(x, y); } void Util::waitMouseUp(void) { diff --git a/engines/gob/video.h b/engines/gob/video.h index 1338885588..e6baf9a67d 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -194,6 +194,15 @@ public: virtual ~Video_v2() {} }; +class Video_v6 : public Video_v2 { +public: + virtual char spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight, + int16 x, int16 y, int16 transp, SurfaceDesc *destDesc); + + Video_v6(GobEngine *vm); + virtual ~Video_v6() {} +}; + class VideoDriver { public: VideoDriver() {} diff --git a/engines/gob/video_v6.cpp b/engines/gob/video_v6.cpp new file mode 100644 index 0000000000..434406265e --- /dev/null +++ b/engines/gob/video_v6.cpp @@ -0,0 +1,69 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/video.h" + +namespace Gob { + +Video_v6::Video_v6(GobEngine *vm) : Video_v2(vm) { +} + +char Video_v6::spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight, + int16 x, int16 y, int16 transp, SurfaceDesc *destDesc) { + if (!destDesc) + return 1; + + _vm->validateVideoMode(destDesc->_vidMode); + + if (sprBuf[0] != 1) + return 0; + + if (sprBuf[1] != 3) + return 0; + + sprBuf += 2; + + srcWidth = READ_LE_UINT16(sprBuf); + sprBuf += 2; + srcHeight = READ_LE_UINT16(sprBuf); + sprBuf += 2; + + if (sprBuf[0] == 0) { + SurfaceDesc sourceDesc(0x13, srcWidth, srcHeight, sprBuf + 3); + Video::drawSprite(&sourceDesc, destDesc, 0, 0, srcWidth - 1, + srcHeight - 1, x, y, transp); + return 1; + } else { + warning("Urban Stub: spriteUncompressor()"); + return 0; + } + + return 1; +} + +} // End of namespace Gob diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index aa47e6cf84..daf7bdd801 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -23,6 +23,7 @@ * */ + #include "gob/videoplayer.h" #include "gob/global.h" #include "gob/util.h" @@ -568,7 +569,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_util->processInput(); - if (_vm->_quitRequested) { + if (_vm->quit()) { _primaryVideo->getVideo()->disableSound(); return true; } diff --git a/engines/igor/parts/part_22.cpp b/engines/igor/parts/part_22.cpp index 9727ae3e1a..7a7c26d477 100644 --- a/engines/igor/parts/part_22.cpp +++ b/engines/igor/parts/part_22.cpp @@ -74,7 +74,9 @@ void IgorEngine::PART_22_ACTION_101() { void IgorEngine::PART_22_ACTION_102() { _walkDataCurrentIndex = 0; _walkCurrentFrame = 1; - for (int i = 9; i >= 0; --i) { + int i = 0; + + for (i = 9; i >= 0; --i) { WalkData *wd = &_walkData[0]; wd->setPos(138, 123, 1, _walkCurrentFrame); WalkData::setNextFrame(1, _walkCurrentFrame); @@ -89,7 +91,7 @@ void IgorEngine::PART_22_ACTION_102() { moveIgor(wd->posNum, wd->frameNum); waitForTimer(15); } - int i = 16; + i = 16; do { if (compareGameTick(1, 16)) { memcpy(_screenTextLayer + (i * 8 + 16) * 320, _screenLayer1 + (128 - i * 8) * 320, (i * 8 + 16) * 320); diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index 0c6eb29665..7a377471c1 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -397,6 +397,18 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_FLOPPY_FLAGS }, + { // Floppy version extracted + { + "kyra2", + "Extracted", + AD_ENTRY1("FATE.PAK", "e0a70c31b022cb4bb3061890020fc27c"), + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + KYRA2_FLOPPY_FLAGS + }, + { // CD version { "kyra2", @@ -1052,11 +1064,23 @@ public: return "The Legend of Kyrandia (C) Westwood Studios"; } + bool hasFeature(MetaEngineFeature f) const; bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - SaveStateList listSaves(const char *target) const; + void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; +bool KyraMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave) || + (f == kSupportsMetaInfos) || + (f == kSupportsThumbnails); +} + bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const KYRAGameDescription *gd = (const KYRAGameDescription *)desc; bool res = true; @@ -1107,7 +1131,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { Common::StringList filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) SaveStateList saveList; for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) { @@ -1117,8 +1141,13 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { if (slotNum >= 0 && slotNum <= 999) { Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); if (in) { - if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError) + if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError) { + // Workaround for old savegames using 'German' as description for kyra3 start savegame (slot 0) + if (slotNum == 0 && header.gameID == Kyra::GI_KYRA3) + header.description = "New Game"; + saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file)); + } delete in; } } @@ -1127,8 +1156,69 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const { return saveList; } +void KyraMetaEngine::removeSaveState(const char *target, int slot) const { + // Slot 0 can't be deleted, it's for restarting the game(s) + if (slot == 0) + return; + + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::String filename = Kyra::KyraEngine_v1::getSavegameFilename(target, slot); + + saveFileMan->removeSavefile(filename.c_str()); + + Common::StringList filenames; + Common::String pattern = target; + pattern += ".???"; + filenames = saveFileMan->listSavefiles(pattern.c_str()); + Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + // Rename every slot greater than the deleted slot, + // Also do not rename quicksaves. + if (slotNum > slot && slotNum < 990) { + // FIXME: Our savefile renaming done here is inconsitent with what we do in + // GUI_v2::deleteMenu. While here we rename every slot with a greater equal + // number of the deleted slot to deleted slot, deleted slot + 1 etc., + // we only rename the following slots in GUI_v2::deleteMenu until a slot + // is missing. + saveFileMan->renameSavefile(file->c_str(), filename.c_str()); + + filename = Kyra::KyraEngine_v1::getSavegameFilename(target, ++slot); + } + } + +} + +SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = Kyra::KyraEngine_v1::getSavegameFilename(target, slot); + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str()); + + if (in) { + Kyra::KyraEngine_v1::SaveHeader header; + Kyra::KyraEngine_v1::kReadSaveHeaderError error; + + error = Kyra::KyraEngine_v1::readSaveHeader(in, true, header); + delete in; + + if (error == Kyra::KyraEngine_v1::kRSHENoError) { + SaveStateDescriptor desc(slot, header.description, filename); + + desc.setDeletableFlag(slot != 0); + desc.setThumbnail(header.thumbnail); + + return desc; + } + } + + return SaveStateDescriptor(); +} + #if PLUGIN_ENABLED_DYNAMIC(KYRA) REGISTER_PLUGIN_DYNAMIC(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine); #else REGISTER_PLUGIN_STATIC(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine); #endif + diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index 96ea233025..6864bd9c4d 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -311,8 +311,6 @@ void GUI::updateSaveList() { s1 -= '0'; s2 -= '0'; s3 -= '0'; - if (s1 == 9 && s2 == 9 && s3 == 9) - continue; _saveSlots.push_back(s1*100+s2*10+s3); } @@ -378,9 +376,6 @@ bool MainMenu::getInput() { while (_system->getEventManager()->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _vm->quitGame(); - break; case Common::EVENT_LBUTTONUP: return true; default: diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index 1361bdb399..7db8f52f16 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -32,6 +32,8 @@ #include "common/array.h" #include "common/func.h" +#include "graphics/surface.h" + namespace Kyra { #define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y)) @@ -153,6 +155,8 @@ public: void processHighlights(Menu &menu, int mouseX, int mouseY); + // utilities for thumbnail creation + virtual void createScreenThumbnail(Graphics::Surface &dst) = 0; protected: KyraEngine_v1 *_vm; Screen *_screen; diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index 7d56743af5..a1391320f4 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -33,6 +33,8 @@ #include "common/savefile.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_HoF::loadButtonShapes() { @@ -512,7 +514,7 @@ void KyraEngine_HoF::bookLoop() { showBookPage(); _bookShown = true; - while (_bookShown && !_quitFlag) { + while (_bookShown && !quit()) { checkInput(buttonList); removeInputTop(); @@ -793,6 +795,12 @@ int GUI_HoF::optionsButton(Button *button) { #pragma mark - +void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) { + uint8 screenPal[768]; + _screen->getRealPalette(1, screenPal); + ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, screenPal); +} + void GUI_HoF::setupPalette() { memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); @@ -996,7 +1004,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) { if (_vm->_lang != lang) { _reloadTemporarySave = true; - _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame"); + _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame", 0); _vm->loadCCodeBuffer("C_CODE.XXX"); if (_vm->_flags.isTalkie) _vm->loadOptionsBuffer("OPTIONS.XXX"); diff --git a/engines/kyra/gui_hof.h b/engines/kyra/gui_hof.h index f64336a8f6..a9c0426a2b 100644 --- a/engines/kyra/gui_hof.h +++ b/engines/kyra/gui_hof.h @@ -41,6 +41,8 @@ public: void initStaticData(); int optionsButton(Button *button); + + void createScreenThumbnail(Graphics::Surface &dst); private: const char *getMenuTitle(const Menu &menu); const char *getMenuItemTitle(const MenuItem &menuItem); diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 47ce698e50..4efffb0eda 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -34,9 +34,10 @@ #include "common/config-manager.h" #include "common/savefile.h" -#include "common/events.h" #include "common/system.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_LoK::initMainButtonList() { @@ -199,6 +200,18 @@ GUI_LoK::~GUI_LoK() { delete[] _menu; } +void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) { + uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H]; + if (screen) { + _screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen); + + uint8 screenPal[768]; + _screen->getRealPalette(2, screenPal); + ::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, screenPal); + } + delete[] screen; +} + int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) { while (list) { if (list->flags & 8) { @@ -460,7 +473,7 @@ int GUI_LoK::buttonMenuCallback(Button *caller) { updateAllMenuButtons(); } - while (_displayMenu && !_vm->_quitFlag) { + while (_displayMenu && !_vm->quit()) { Common::Point mouse = _vm->getMousePos(); processHighlights(_menu[_toplevelMenu], mouse.x, mouse.y); processButtonList(_menuButtonList, 0, 0); @@ -485,9 +498,6 @@ void GUI_LoK::getInput() { _mouseWheel = 0; while (_vm->_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _vm->quitGame(); - break; case Common::EVENT_LBUTTONDOWN: _vm->_mousePressFlag = true; break; @@ -583,7 +593,7 @@ int GUI_LoK::saveGameMenu(Button *button) { _displaySubMenu = true; _cancelSubMenu = false; - while (_displaySubMenu && !_vm->_quitFlag) { + while (_displaySubMenu && !_vm->quit()) { getInput(); Common::Point mouse = _vm->getMousePos(); processHighlights(_menu[2], mouse.x, mouse.y); @@ -632,7 +642,7 @@ int GUI_LoK::loadGameMenu(Button *button) { _vm->_gameToLoad = -1; - while (_displaySubMenu && !_vm->_quitFlag) { + while (_displaySubMenu && !_vm->quit()) { getInput(); Common::Point mouse = _vm->getMousePos(); processHighlights(_menu[2], mouse.x, mouse.y); @@ -720,7 +730,7 @@ int GUI_LoK::saveGame(Button *button) { } redrawTextfield(); - while (_displaySubMenu && !_vm->_quitFlag) { + while (_displaySubMenu && !_vm->quit()) { getInput(); updateSavegameString(); Common::Point mouse = _vm->getMousePos(); @@ -736,8 +746,12 @@ int GUI_LoK::saveGame(Button *button) { } else { if (_savegameOffset == 0 && _vm->_gameToLoad == 0) _vm->_gameToLoad = getNextSavegameSlot(); - if (_vm->_gameToLoad > 0) - _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName); + if (_vm->_gameToLoad > 0) { + Graphics::Surface thumb; + createScreenThumbnail(thumb); + _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName, &thumb); + thumb.free(); + } } return 0; @@ -796,7 +810,7 @@ bool GUI_LoK::quitConfirm(const char *str) { _displaySubMenu = true; _cancelSubMenu = true; - while (_displaySubMenu && !_vm->_quitFlag) { + while (_displaySubMenu && !_vm->quit()) { getInput(); Common::Point mouse = _vm->getMousePos(); processHighlights(_menu[1], mouse.x, mouse.y); @@ -862,7 +876,7 @@ int GUI_LoK::gameControlsMenu(Button *button) { _displaySubMenu = true; _cancelSubMenu = false; - while (_displaySubMenu && !_vm->_quitFlag) { + while (_displaySubMenu && !_vm->quit()) { getInput(); Common::Point mouse = _vm->getMousePos(); processHighlights(_menu[5], mouse.x, mouse.y); diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 16b7ef9183..0ce718d7a7 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -103,6 +103,8 @@ public: int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel); int buttonMenuCallback(Button *caller); + + void createScreenThumbnail(Graphics::Surface &dst); private: void initStaticResource(); diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index 6822b303c3..72f214f001 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -33,6 +33,8 @@ #include "common/savefile.h" +#include "graphics/scaler.h" + namespace Kyra { void KyraEngine_MR::loadButtonShapes() { @@ -868,7 +870,7 @@ void KyraEngine_MR::processAlbum() { albumNewPage(); _album.running = true; - while (_album.running && !_quitFlag) { + while (_album.running && !quit()) { updateInput(); checkInput(buttonList); removeInputTop(); @@ -1138,6 +1140,12 @@ int KyraEngine_MR::albumClose(Button *caller) { GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) { } +void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) { + uint8 screenPal[768]; + _screen->getRealPalette(0, screenPal); + ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, screenPal); +} + void GUI_MR::flagButtonEnable(Button *button) { if (!button) return; @@ -1450,7 +1458,7 @@ int GUI_MR::gameOptions(Button *caller) { if (_vm->_lang != lang) { _reloadTemporarySave = true; - _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame"); + _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame", 0); if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile)) error("Couldn't load ITEMS"); if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile)) diff --git a/engines/kyra/gui_mr.h b/engines/kyra/gui_mr.h index 5bd3569031..a78d0559a6 100644 --- a/engines/kyra/gui_mr.h +++ b/engines/kyra/gui_mr.h @@ -47,6 +47,8 @@ public: int redrawButtonCallback(Button *button); int optionsButton(Button *button); + + void createScreenThumbnail(Graphics::Surface &dst); private: void getInput(); diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index e4cec760fa..077e49ebcf 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -35,6 +35,7 @@ namespace Kyra { GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI(vm), _vm(vm), _screen(vm->screen_v2()) { _backUpButtonList = _unknownButtonList = 0; _buttonListChanged = false; + _lastScreenUpdate = 0; _currentMenu = 0; _isDeathMenu = false; @@ -618,7 +619,12 @@ int GUI_v2::saveMenu(Button *caller) { restorePage1(_vm->_screenBuffer); restorePalette(); - _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription); + + Graphics::Surface thumb; + createScreenThumbnail(thumb); + _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription, &thumb); + thumb.free(); + _displayMenu = false; _madeSave = true; @@ -762,6 +768,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 x2 -= getCharWidth(buffer[curPos]); drawTextfieldBlock(x2, y2, c3); _screen->updateScreen(); + _lastScreenUpdate = _vm->_system->getMillis(); } else if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127 && curPos < bufferSize) { if (x2 + getCharWidth(_keyPressed.ascii) + 7 < 0x11F) { buffer[curPos] = _keyPressed.ascii; @@ -771,6 +778,7 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 drawTextfieldBlock(x2, y2, c3); ++curPos; _screen->updateScreen(); + _lastScreenUpdate = _vm->_system->getMillis(); } } @@ -818,17 +826,15 @@ int GUI_v2::getCharWidth(uint8 c) { void GUI_v2::checkTextfieldInput() { Common::Event event; + uint32 now = _vm->_system->getMillis(); + bool running = true; int keys = 0; while (_vm->_eventMan->pollEvent(event) && running) { switch (event.type) { - case Common::EVENT_QUIT: - _vm->_quitFlag = true; - break; - case Common::EVENT_KEYDOWN: if (event.kbd.keycode == 'q' && event.kbd.flags == Common::KBD_CTRL) - _vm->_quitFlag = true; + _vm->quitGame(); else _keyPressed = event.kbd; running = false; @@ -848,6 +854,7 @@ void GUI_v2::checkTextfieldInput() { _vm->_mouseX = pos.x; _vm->_mouseY = pos.y; _screen->updateScreen(); + _lastScreenUpdate = now; } break; default: @@ -855,7 +862,13 @@ void GUI_v2::checkTextfieldInput() { } } + if (now - _lastScreenUpdate > 50) { + _vm->_system->updateScreen(); + _lastScreenUpdate = now; + } + processButtonList(_menuButtonList, keys | 0x8000, 0); + _vm->_system->delayMillis(3); } void GUI_v2::drawTextfieldBlock(int x, int y, uint8 c) { diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index 60b7f0ab86..88861ff905 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -213,6 +213,7 @@ protected: // savename menu bool _finishNameInput, _cancelNameInput; Common::KeyState _keyPressed; + uint32 _lastScreenUpdate; const char *nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 c2, uint8 c3, int bufferSize); int finishSavename(Button *caller); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 33a8af91f1..76d6f6ea05 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -306,8 +306,10 @@ int KyraEngine_HoF::go() { _res->loadFileList(_ingamePakList, _ingamePakListSize); } - if (_flags.platform == Common::kPlatformPC98) + if (_flags.platform == Common::kPlatformPC98) { _res->loadPakFile("AUDIO.PAK"); + _sound->loadSoundFile("sound.dat"); + } } _menuDirectlyToLoad = (_menuChoice == 3) ? true : false; @@ -434,7 +436,7 @@ void KyraEngine_HoF::startup() { if (_gameToLoad == -1) { snd_playWanderScoreViaMap(52, 1); enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1); - saveGame(getSavegameFilename(0), "New Game"); + saveGame(getSavegameFilename(0), "New Game", 0); } else { loadGame(getSavegameFilename(_gameToLoad)); } @@ -452,17 +454,21 @@ void KyraEngine_HoF::startup() { void KyraEngine_HoF::runLoop() { _screen->updateScreen(); - _quitFlag = false; _runFlag = true; - while (!_quitFlag && _runFlag) { + while (!quit() && _runFlag) { if (_deathHandler >= 0) { removeHandItem(); delay(5); _drawNoShapeFlag = 0; _gui->optionsButton(0); _deathHandler = -1; + + if (!_runFlag || !quit()) + break; } + checkAutosave(); + if (_system->getMillis() > _nextIdleAnim) showIdleAnim(); @@ -1578,10 +1584,14 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) { int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]); if (vocIndex != -1) _sound->voicePlay(_ingameSoundList[vocIndex], true); - else if (_flags.platform != Common::kPlatformFMTowns) + else if (_flags.platform == Common::kPlatformPC) + KyraEngine_v1::snd_playSoundEffect(track); + // TODO ?? Maybe there is a way to let users select whether they want // voc, midi or adl sfx (even though it makes no sense to choose anything but voc). - KyraEngine_v1::snd_playSoundEffect(track); + // The PC-98 version has support for non-pcm sound effects, but only for tracks + // which also have voc files. The syntax would be: + // KyraEngine_v1::snd_playSoundEffect(vocIndex); } #pragma mark - @@ -1620,7 +1630,7 @@ void KyraEngine_HoF::loadInvWsa(const char *filename, int run, int delayTime, in _invWsa.timer = _system->getMillis(); if (run) { - while (_invWsa.running && !skipFlag() && !_quitFlag) { + while (_invWsa.running && !skipFlag() && !quit()) { update(); _system->delayMillis(10); } @@ -1994,7 +2004,7 @@ void KyraEngine_HoF::playTim(const char *filename) { return; _tim->resetFinishedFlag(); - while (!_quitFlag && !_tim->finished()) { + while (!quit() && !_tim->finished()) { _tim->exec(tim, 0); if (_chatText) updateWithText(); diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index f6e887c648..dc4161f0c1 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -907,7 +907,7 @@ protected: int _dbgPass; // save/load specific - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); }; diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index c852f6e3ee..f71cc8f409 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -26,7 +26,6 @@ #include "kyra/kyra_lok.h" #include "common/file.h" -#include "common/events.h" #include "common/system.h" #include "common/savefile.h" @@ -119,8 +118,12 @@ KyraEngine_LoK::~KyraEngine_LoK() { delete[] _characterList; + delete[] _roomTable; + delete[] _movFacingTable; + delete[] _defaultShapeTable; + delete[] _gui->_scrollUpButton.data0ShapePtr; delete[] _gui->_scrollUpButton.data1ShapePtr; delete[] _gui->_scrollUpButton.data2ShapePtr; @@ -300,7 +303,7 @@ int KyraEngine_LoK::go() { if (_gameToLoad == -1) { setGameFlag(0xEF); seq_intro(); - if (_quitFlag) + if (quit()) return 0; if (_skipIntroFlag && _abortIntroFlag) resetGameFlag(0xEF); @@ -388,7 +391,7 @@ void KyraEngine_LoK::startup() { _gui->buttonMenuCallback(0); _menuDirectlyToLoad = false; } else - saveGame(getSavegameFilename(0), "New game"); + saveGame(getSavegameFilename(0), "New game", 0); } else { _screen->setFont(Screen::FID_8_FNT); loadGame(getSavegameFilename(_gameToLoad)); @@ -399,10 +402,12 @@ void KyraEngine_LoK::startup() { void KyraEngine_LoK::mainLoop() { debugC(9, kDebugLevelMain, "KyraEngine_LoK::mainLoop()"); - while (!_quitFlag) { + while (!quit()) { int32 frameTime = (int32)_system->getMillis(); _skipFlag = false; + checkAutosave(); + if (_currentCharacter->sceneId == 210) { updateKyragemFading(); if (seq_playEnd() && _deathHandler != 8) @@ -444,7 +449,7 @@ void KyraEngine_LoK::mainLoop() { } void KyraEngine_LoK::delayUntil(uint32 timestamp, bool updateTimers, bool update, bool isMainLoop) { - while (_system->getMillis() < timestamp && !_quitFlag) { + while (_system->getMillis() < timestamp && !quit()) { if (updateTimers) _timer->update(); @@ -470,13 +475,13 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) { else { char savegameName[14]; sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); - saveGame(saveLoadSlot, savegameName); + saveGame(saveLoadSlot, savegameName, 0); } } else if (event.kbd.flags == Common::KBD_CTRL) { if (event.kbd.keycode == 'd') _debugger->attach(); else if (event.kbd.keycode == 'q') - _quitFlag = true; + quitGame(); } else if (event.kbd.keycode == '.') { _skipFlag = true; } else if (event.kbd.keycode == Common::KEYCODE_RETURN || event.kbd.keycode == Common::KEYCODE_SPACE || event.kbd.keycode == Common::KEYCODE_ESCAPE) { @@ -488,9 +493,6 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) { case Common::EVENT_MOUSEMOVE: _animator->_updateScreen = true; break; - case Common::EVENT_QUIT: - quitGame(); - break; case Common::EVENT_LBUTTONDOWN: _mousePressFlag = true; break; @@ -529,27 +531,24 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) { if (_skipFlag && !_abortIntroFlag && !queryGameFlag(0xFE)) _skipFlag = false; - if (amount > 0 && !_skipFlag && !_quitFlag) + if (amount > 0 && !_skipFlag && !quit()) _system->delayMillis(10); if (_skipFlag) _sound->voiceStop(); - } while (!_skipFlag && _system->getMillis() < start + amount && !_quitFlag); + } while (!_skipFlag && _system->getMillis() < start + amount && !quit()); } void KyraEngine_LoK::waitForEvent() { bool finished = false; Common::Event event; - while (!finished && !_quitFlag) { + while (!finished && !quit()) { while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: finished = true; break; - case Common::EVENT_QUIT: - quitGame(); - break; case Common::EVENT_LBUTTONDOWN: finished = true; _skipFlag = true; diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index 1def95ddbf..e6fc0dc774 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -214,7 +214,7 @@ public: protected: int32 _speechPlayTime; - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); protected: diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index a61253199b..9d3171e723 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -263,7 +263,7 @@ int KyraEngine_MR::go() { running = false; } - while (running && !_quitFlag) { + while (running && !quit()) { _screen->_curPage = 0; _screen->clearPage(0); @@ -272,14 +272,14 @@ int KyraEngine_MR::go() { // XXX playMenuAudioFile(); - for (int i = 0; i < 64 && !_quitFlag; ++i) { + for (int i = 0; i < 64 && !quit(); ++i) { uint32 nextRun = _system->getMillis() + 3 * _tickLength; _menuAnim->displayFrame(i, 0); _screen->updateScreen(); delayUntil(nextRun); } - for (int i = 64; i > 29 && !_quitFlag; --i) { + for (int i = 64; i > 29 && !quit(); --i) { uint32 nextRun = _system->getMillis() + 3 * _tickLength; _menuAnim->displayFrame(i, 0); _screen->updateScreen(); @@ -684,7 +684,7 @@ void KyraEngine_MR::startup() { assert(_invWsa); _invWsa->open("MOODOMTR.WSA", 1, 0); _invWsaFrame = 6; - saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33)); + saveGame(getSavegameFilename(0), "New Game", 0); _soundDigital->beginFadeOut(_musicSoundChannel, 60); delayWithTicks(60); if (_gameToLoad == -1) @@ -1001,14 +1001,19 @@ void KyraEngine_MR::runLoop() { _eventList.clear(); _runFlag = true; - while (_runFlag && !_quitFlag) { + while (_runFlag && !quit()) { if (_deathHandler >= 0) { removeHandItem(); delay(5); _drawNoShapeFlag = 0; _gui->optionsButton(0); _deathHandler = -1; + + if (quit()) + break; } + + checkAutosave(); if (_system->getMillis() >= _nextIdleAnim) showIdleAnim(); diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 5f9f6f91a3..a6fb9af20c 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -583,7 +583,7 @@ private: int albumClose(Button *caller); // save/load - void saveGame(const char *fileName, const char *saveName); + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail); void loadGame(const char *fileName); // opcodes diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index bc46d8e1f5..8162232935 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -52,8 +52,6 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) _gameSpeed = 60; _tickLength = (uint8)(1000.0 / _gameSpeed); - _quitFlag = false; - _speechFile = ""; _trackMap = 0; _trackMapSize = 0; @@ -183,6 +181,9 @@ int KyraEngine_v1::init() { _gameToLoad = -1; } + // Prevent autosave on game startup + _lastAutosave = _system->getMillis(); + return 0; } @@ -200,12 +201,6 @@ KyraEngine_v1::~KyraEngine_v1() { delete _debugger; } -void KyraEngine_v1::quitGame() { - debugC(9, kDebugLevelMain, "KyraEngine_v1::quitGame()"); - _quitFlag = true; - // Nothing to do here -} - Common::Point KyraEngine_v1::getMousePos() const { Common::Point mouse = _eventMan->getMousePos(); @@ -240,7 +235,7 @@ int KyraEngine_v1::resetGameFlag(int flag) { } void KyraEngine_v1::delayUntil(uint32 timestamp, bool updateTimers, bool update, bool isMainLoop) { - while (_system->getMillis() < timestamp && !_quitFlag) { + while (_system->getMillis() < timestamp && !quit()) { if (timestamp - _system->getMillis() >= 10) delay(10, update, isMainLoop); } @@ -255,8 +250,8 @@ void KyraEngine_v1::delayWithTicks(int ticks) { } void KyraEngine_v1::registerDefaultSettings() { - if (_flags.gameID != GI_KYRA3) - ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)); + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) + ConfMan.registerDefault("cdaudio", true); if (_flags.fanLang != Common::UNK_LANG) { // HACK/WORKAROUND: Since we can't use registerDefault here to overwrite // the global subtitles settings, we're using this hack to enable subtitles @@ -272,9 +267,10 @@ void KyraEngine_v1::readSettings() { _configMusic = 0; if (!ConfMan.getBool("music_mute")) { - _configMusic = 1; - if (_flags.gameID != GI_KYRA3 && ConfMan.getBool("cdaudio") && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) - _configMusic = 2; + if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) + _configMusic = ConfMan.getBool("cdaudio") ? 2 : 1; + else + _configMusic = 1; } _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1; diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 738a3fc8ec..f4c2442c0e 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -118,8 +118,6 @@ public: virtual void pauseEngineIntern(bool pause); - bool quit() const { return _quitFlag; } - uint8 game() const { return _flags.gameID; } const GameFlags &gameFlags() const { return _flags; } @@ -153,9 +151,6 @@ public: void setVolume(kVolumeEntry vol, uint8 value); uint8 getVolume(kVolumeEntry vol); - // quit handling - virtual void quitGame(); - // game flag handling int setGameFlag(int flag); int queryGameFlag(int flag) const; @@ -178,9 +173,6 @@ protected: virtual int go() = 0; virtual int init(); - // quit Handling - bool _quitFlag; - // intern Resource *_res; Sound *_sound; @@ -279,7 +271,11 @@ protected: // save/load int _gameToLoad; + uint32 _lastAutosave; + void checkAutosave(); + const char *getSavegameFilename(int num); + static Common::String getSavegameFilename(const Common::String &target, int num); bool saveFileLoadable(int slot); struct SaveHeader { @@ -290,6 +286,8 @@ protected: bool originalSave; // savegame from original interpreter bool oldHeader; // old scummvm save header + + Graphics::Surface *thumbnail; }; enum kReadSaveHeaderError { @@ -299,10 +297,12 @@ protected: kRSHEIoError = 3 }; - static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header); + static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header); + + virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0; Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header); - Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const; + Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const; }; } // End of namespace Kyra diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index 2e704f2aa2..e9ed91b539 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -159,7 +159,7 @@ void KyraEngine_v2::delay(uint32 amount, bool updateGame, bool isMainLoop) { if (amount > 0) _system->delayMillis(amount > 10 ? 10 : amount); - } while (!skipFlag() && _system->getMillis() < start + amount && !_quitFlag); + } while (!skipFlag() && _system->getMillis() < start + amount && !quit()); } int KyraEngine_v2::checkInput(Button *buttonList, bool mainLoop) { @@ -186,7 +186,7 @@ int KyraEngine_v2::checkInput(Button *buttonList, bool mainLoop) { } else { char savegameName[14]; sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0'); - saveGame(saveLoadSlot, savegameName); + saveGame(saveLoadSlot, savegameName, 0); } } else if (event.kbd.flags == Common::KBD_CTRL) { if (event.kbd.keycode == 'd') @@ -238,15 +238,11 @@ void KyraEngine_v2::updateInput() { while (_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _quitFlag = true; - break; - case Common::EVENT_KEYDOWN: if (event.kbd.keycode == '.' || event.kbd.keycode == Common::KEYCODE_ESCAPE) _eventList.push_back(Event(event, true)); else if (event.kbd.keycode == 'q' && event.kbd.flags == Common::KBD_CTRL) - _quitFlag = true; + quitGame(); else _eventList.push_back(event); break; diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index 6fdf30fff8..e7f9634fc6 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -419,7 +419,7 @@ protected: int o2_getVocHigh(EMCState *script); // save/load specific - virtual void saveGame(const char *fileName, const char *saveName) = 0; + virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0; virtual void loadGame(const char *fileName) = 0; }; diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 6624dd91ea..053d8a4de9 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -183,15 +183,11 @@ void LoLEngine::updateInput() { while (_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _quitFlag = true; - break; - case Common::EVENT_KEYDOWN: if (event.kbd.keycode == '.' || event.kbd.keycode == Common::KEYCODE_ESCAPE) _eventList.push_back(Event(event, true)); else if (event.kbd.keycode == 'q' && event.kbd.flags == Common::KBD_CTRL) - _quitFlag = true; + quitGame(); else _eventList.push_back(event); break; @@ -245,27 +241,21 @@ void LoLEngine::resetSkipFlag(bool removeEvent) { void LoLEngine::setupPrologueData(bool load) { static const char * const fileList[] = { - "xxx/general.pak", - "xxx/introvoc.pak", - "xxx/startup.pak", - "xxx/intro1.pak", - "xxx/intro2.pak", - "xxx/intro3.pak", - "xxx/intro4.pak", - "xxx/intro5.pak", - "xxx/intro6.pak", - "xxx/intro7.pak", - "xxx/intro8.pak", - "xxx/intro9.pak" + "GENERAL.PAK", "INTROVOC.PAK", "STARTUP.PAK", "INTRO1.PAK", + "INTRO2.PAK", "INTRO3.PAK", "INTRO4.PAK", "INTRO5.PAK", + "INTRO6.PAK", "INTRO7.PAK", "INTRO8.PAK", "INTRO9.PAK" }; - char filepath[32]; - char *filename = filepath; + char filename[32]; for (uint i = 0; i < ARRAYSIZE(fileList); ++i) { - strcpy(filename, fileList[i]); - memcpy(filename, _languageExt[_lang], 3); - if (!_flags.isTalkie) - filename += 4; + filename[0] = '\0'; + + if (_flags.isTalkie) { + strcpy(filename, _languageExt[_lang]); + strcat(filename, "/"); + } + + strcat(filename, fileList[i]); if (load) { if (!_res->loadPakFile(filename)) @@ -307,7 +297,7 @@ void LoLEngine::showIntro() { _screen->hideMouse(); uint32 palNextFadeStep = 0; - while (!_tim->finished() && !_quitFlag && !skipFlag()) { + while (!_tim->finished() && !quit() && !skipFlag()) { updateInput(); _tim->exec(intro, false); _screen->checkedPageUpdate(8, 4); @@ -385,14 +375,14 @@ int LoLEngine::chooseCharacter() { _screen->fadePalette(_screen->getPalette(0), 30, 0); bool kingIntro = true; - while (!_quitFlag) { + while (!quit()) { if (kingIntro) kingSelectionIntro(); if (_charSelection < 0) processCharacterSelection(); - if (_quitFlag) + if (quit()) break; if (_charSelection == 100) { @@ -413,11 +403,11 @@ int LoLEngine::chooseCharacter() { } } - if (_quitFlag) + if (quit()) return -1; uint32 waitTime = _system->getMillis() + 420 * _tickLength; - while (waitTime > _system->getMillis() && !skipFlag() && !_quitFlag) { + while (waitTime > _system->getMillis() && !skipFlag() && !quit()) { updateInput(); _system->delayMillis(10); } @@ -449,7 +439,7 @@ void LoLEngine::kingSelectionIntro() { _chargenWSA->setDrawPage(0); int index = 4; - while (_sound->voiceIsPlaying("KING01") && _charSelection == -1 && !_quitFlag && !skipFlag()) { + while (_sound->voiceIsPlaying("KING01") && _charSelection == -1 && !quit() && !skipFlag()) { index = MAX(index, 4); _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0); @@ -460,7 +450,7 @@ void LoLEngine::kingSelectionIntro() { _screen->updateScreen(); uint32 waitEnd = _system->getMillis() + 7 * _tickLength; - while (waitEnd > _system->getMillis() && _charSelection == -1 && !_quitFlag && !skipFlag()) { + while (waitEnd > _system->getMillis() && _charSelection == -1 && !quit() && !skipFlag()) { _charSelection = getCharSelection(); _system->delayMillis(10); } @@ -491,7 +481,7 @@ void LoLEngine::kingSelectionReminder() { _chargenWSA->setDrawPage(0); int index = 0; - while (_sound->voiceIsPlaying("KING02") && _charSelection == -1 && !_quitFlag && index < 15) { + while (_sound->voiceIsPlaying("KING02") && _charSelection == -1 && !quit() && index < 15) { _chargenWSA->displayFrame(_chargenFrameTable[index+9], 0, 0, 0); _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index]*2+0], _selectionPosTable[_reminderChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0); _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index]*2+0], _selectionPosTable[_reminderChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0); @@ -500,7 +490,7 @@ void LoLEngine::kingSelectionReminder() { _screen->updateScreen(); uint32 waitEnd = _system->getMillis() + 8 * _tickLength; - while (waitEnd > _system->getMillis() && !_quitFlag) { + while (waitEnd > _system->getMillis() && !quit()) { _charSelection = getCharSelection(); _system->delayMillis(10); } @@ -521,14 +511,14 @@ void LoLEngine::kingSelectionOutro() { _chargenWSA->setDrawPage(0); int index = 0; - while (_sound->voiceIsPlaying("KING03") && !_quitFlag && !skipFlag()) { + while (_sound->voiceIsPlaying("KING03") && !quit() && !skipFlag()) { index = MAX(index, 4); _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0); _screen->updateScreen(); uint32 waitEnd = _system->getMillis() + 8 * _tickLength; - while (waitEnd > _system->getMillis() && !_quitFlag && !skipFlag()) { + while (waitEnd > _system->getMillis() && !quit() && !skipFlag()) { updateInput(); _system->delayMillis(10); } @@ -547,10 +537,10 @@ void LoLEngine::processCharacterSelection() { debugC(9, kDebugLevelMain, "LoLEngine::processCharacterSelection()"); _charSelection = -1; - while (!_quitFlag && _charSelection == -1) { + while (!quit() && _charSelection == -1) { uint32 nextKingMessage = _system->getMillis() + 900 * _tickLength; - while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !_quitFlag) { + while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !quit()) { updateSelectionAnims(); _charSelection = getCharSelection(); _system->delayMillis(10); @@ -595,22 +585,22 @@ int LoLEngine::selectionCharInfo(int character) { switch (character) { case 0: - strcpy(filename, "face09.shp"); + strcpy(filename, "FACE09.SHP"); vocFilename[3] = 'A'; break; case 1: - strcpy(filename, "face01.shp"); + strcpy(filename, "FACE01.SHP"); vocFilename[3] = 'M'; break; case 2: - strcpy(filename, "face08.shp"); + strcpy(filename, "FACE08.SHP"); vocFilename[3] = 'K'; break; case 3: - strcpy(filename, "face05.shp"); + strcpy(filename, "FACE05.SHP"); vocFilename[3] = 'C'; break; @@ -669,12 +659,12 @@ void LoLEngine::selectionCharInfoIntro(char *file) { int index = 0; file[4] = '0'; - while (_charSelectionInfoResult == -1 && !_quitFlag) { + while (_charSelectionInfoResult == -1 && !quit()) { if (!_sound->voicePlay(file)) break; int i = 0; - while (_sound->voiceIsPlaying(file) && _charSelectionInfoResult == -1 && !_quitFlag) { + while (_sound->voiceIsPlaying(file) && _charSelectionInfoResult == -1 && !quit()) { _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), _charInfoFrameTable[i]), 11, 130, 0, 0); _screen->updateScreen(); diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index ee54f8abbb..2ae4d71580 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -147,6 +147,9 @@ private: void setHandItem(uint16) {} void removeHandItem() {} bool lineIsPassable(int, int) { return false; } + + // save + void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) {} }; } // end of namespace Kyra diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index e059a8ce4b..b38661ada5 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -23,6 +23,7 @@ MODULE_OBJS := \ kyra_mr.o \ lol.o \ resource.o \ + resource_intern.o \ saveload.o \ saveload_lok.o \ saveload_hof.o \ diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 5da6bb3873..0f0a643017 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -23,39 +23,46 @@ * */ +#include "kyra/resource.h" +#include "kyra/resource_intern.h" #include "common/config-manager.h" #include "common/endian.h" #include "common/file.h" #include "common/fs.h" #include "common/func.h" - -#include "kyra/resource.h" +#include "common/system.h" namespace Kyra { -Resource::Resource(KyraEngine_v1 *vm) : _loaders(), _map(), _vm(vm) { +Resource::Resource(KyraEngine_v1 *vm) : _archiveCache(), _files(), _archiveFiles(new Common::SearchSet()), _protectedFiles(new Common::SearchSet()), _loaders(), _vm(vm) { initializeLoaders(); + + Common::SharedPtr<Common::Archive> path(new Common::FSDirectory(ConfMan.get("path"), 2)); + Common::SharedPtr<Common::Archive> extrapath(new Common::FSDirectory(ConfMan.get("extrapath"))); + + _files.add("path", path, 4); + _files.add("extrapath", extrapath, 4); + _vm->_system->addSysArchivesToSearchSet(_files, 3); + // compressed installer archives are added at level '2', + // but that's done in Resource::reset not here + _files.add("protected", _protectedFiles, 1); + _files.add("archives", _archiveFiles, 0); } Resource::~Resource() { - _map.clear(); _loaders.clear(); - - clearCompFileList(); - _compLoaders.clear(); } bool Resource::reset() { - clearCompFileList(); unloadAllPakFiles(); - FilesystemNode dir(ConfMan.get("path")); + Common::FilesystemNode dir(ConfMan.get("path")); if (!dir.exists() || !dir.isDirectory()) error("invalid game path '%s'", dir.getPath().c_str()); - if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) { + if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat(this)) { Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website"; _vm->GUIErrorMessage(errorMessage); error(errorMessage.c_str()); @@ -65,24 +72,14 @@ bool Resource::reset() { // We only need kyra.dat for the demo. if (_vm->gameFlags().isDemo) return true; - - // only VRM file we need in the *whole* game for kyra1 - if (_vm->gameFlags().isTalkie) - loadPakFile("CHAPTER1.VRM"); } else if (_vm->game() == GI_KYRA2) { if (_vm->gameFlags().useInstallerPackage) - tryLoadCompFiles(); + _files.add("installer", loadInstallerArchive("WESTWOOD", "%03d", 6), 2); // mouse pointer, fonts, etc. required for initializing if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) { loadPakFile("GENERAL.PAK"); } else { - if (_vm->gameFlags().isTalkie) { - // Add default file directories - Common::File::addDefaultDirectory(ConfMan.get("path") + "hof_cd"); - Common::File::addDefaultDirectory(ConfMan.get("path") + "HOF_CD"); - } - loadPakFile("INTROGEN.PAK"); loadPakFile("OTHER.PAK"); } @@ -94,23 +91,19 @@ bool Resource::reset() { error("couldn't load file: 'WESTWOOD.001'"); } - // Add default file directories - Common::File::addDefaultDirectory(ConfMan.get("path") + "malcolm"); - Common::File::addDefaultDirectory(ConfMan.get("path") + "MALCOLM"); - if (!loadFileList("FILEDATA.FDT")) error("couldn't load file: 'FILEDATA.FDT'"); return true; } else if (_vm->game() == GI_LOL) { if (_vm->gameFlags().useInstallerPackage) - tryLoadCompFiles(); + _files.add("installer", loadInstallerArchive("WESTWOOD", "%d", 0), 2); return true; } - FSList fslist; - if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) + Common::FSList fslist; + if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) error("can't list files inside game path '%s'", dir.getPath().c_str()); if (_vm->game() == GI_KYRA1 && _vm->gameFlags().isTalkie) { @@ -120,15 +113,13 @@ bool Resource::reset() { "CAVE.APK", "DRAGON1.APK", "DRAGON2.APK", "LAGOON.APK" }; - Common::for_each(list, list + ARRAYSIZE(list), Common::bind1st(Common::mem_fun(&Resource::loadPakFile), this)); - - for (int i = 0; i < ARRAYSIZE(list); ++i) { - ResFileMap::iterator iterator = _map.find(list[i]); - if (iterator != _map.end()) - iterator->_value.prot = true; + for (uint i = 0; i < ARRAYSIZE(list); ++i) { + Common::ArchivePtr archive = loadArchive(list[i]); + if (archive) + _protectedFiles->add(list[i], archive, 0); } } else { - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { Common::String filename = file->getName(); filename.toUppercase(); @@ -149,113 +140,55 @@ bool Resource::reset() { return true; } -bool Resource::loadPakFile(const Common::String &filename) { - if (!isAccessable(filename)) - return false; - - ResFileMap::iterator iter = _map.find(filename); - if (iter == _map.end()) - return false; +bool Resource::loadPakFile(Common::String filename) { + filename.toUppercase(); - if (iter->_value.preload) { - iter->_value.mounted = true; + if (_archiveFiles->hasArchive(filename) || _protectedFiles->hasArchive(filename)) return true; - } - const ResArchiveLoader *loader = getLoader(iter->_value.type); - if (!loader) { - error("no archive loader for file '%s' found which is of type %d", filename.c_str(), iter->_value.type); + Common::ArchivePtr archive = loadArchive(filename); + if (!archive) return false; - } - Common::SeekableReadStream *stream = getFileStream(filename); - if (!stream) { - error("archive file '%s' not found", filename.c_str()); - return false; - } + _archiveFiles->add(filename, archive, 0); - iter->_value.mounted = true; - iter->_value.preload = true; - ResArchiveLoader::FileList files; - loader->loadFile(filename, *stream, files); - delete stream; - stream = 0; - - for (ResArchiveLoader::FileList::iterator i = files.begin(); i != files.end(); ++i) { - iter = _map.find(i->filename); - if (iter == _map.end()) { - // We do an internal check for a file in gamepath with same filename to - // allow overwriting files inside archives with plain files inside the - // game directory - checkFile(i->filename); - - // A new file entry, so we just insert it into the file map. - if (_map.find(i->filename) == _map.end()) - _map[i->filename] = i->entry; - } else if (!iter->_value.parent.empty()) { - if (!iter->_value.parent.equalsIgnoreCase(filename)) { - ResFileMap::iterator oldParent = _map.find(iter->_value.parent); - if (oldParent != _map.end()) { - // Protected files and their embedded file entries do not get overwritten. - if (!oldParent->_value.prot) { - // If the old parent is not protected we mark it as not preload anymore, - // since now no longer all of its embedded files are in the filemap. - oldParent->_value.preload = false; - _map[i->filename] = i->entry; - } - } else { - // Old parent not found? That's strange... But we just overwrite the old - // entry. - _map[i->filename] = i->entry; - } - } else { - // The old parent has the same filenames as the new archive, we are sure and overwrite the - // old file entry, could be afterall that the preload flag of the new archive was - // just unflagged. - _map[i->filename] = i->entry; - } - } - // 'else' case would mean here overwriting an existing file entry in the map without parent. - // We don't support that though, so one can overwrite files from archives by putting - // them in the gamepath. - } - - detectFileTypes(); return true; } bool Resource::loadFileList(const Common::String &filedata) { - Common::File f; + Common::SeekableReadStream *f = getFileStream(filedata); - if (!f.open(filedata)) + if (!f) return false; uint32 filenameOffset = 0; - while ((filenameOffset = f.readUint32LE()) != 0) { - uint32 offset = f.pos(); - f.seek(filenameOffset, SEEK_SET); + while ((filenameOffset = f->readUint32LE()) != 0) { + uint32 offset = f->pos(); + f->seek(filenameOffset, SEEK_SET); uint8 buffer[13]; - f.read(buffer, sizeof(buffer)-1); + f->read(buffer, sizeof(buffer)-1); buffer[12] = 0; - f.seek(offset + 16, SEEK_SET); + f->seek(offset + 16, SEEK_SET); - Common::String filename = Common::String((char*)buffer); + Common::String filename = Common::String((char *)buffer); filename.toUppercase(); if (filename.hasSuffix(".PAK")) { - if (!isAccessable(filename) && _vm->gameFlags().isDemo) { + if (!exists(filename.c_str()) && _vm->gameFlags().isDemo) { // the demo version supplied with Kyra3 does not // contain all pak files listed in filedata.fdt // so we don't do anything here if they are non // existant. } else if (!loadPakFile(filename)) { + delete f; error("couldn't load file '%s'", filename.c_str()); return false; } } } + delete f; return true; } @@ -273,33 +206,21 @@ bool Resource::loadFileList(const char * const *filelist, uint32 numFiles) { return true; } -void Resource::unloadPakFile(const Common::String &filename) { - ResFileMap::iterator iter = _map.find(filename); - if (iter != _map.end()) { - if (!iter->_value.prot) - iter->_value.mounted = false; - } -} - -void Resource::clearCompFileList() { - for (CompFileMap::iterator i = _compFiles.begin(); i != _compFiles.end(); ++i) - delete[] i->_value.data; - - _compFiles.clear(); +void Resource::unloadPakFile(Common::String filename) { + filename.toUppercase(); + _archiveFiles->remove(filename); + // We do not remove files from '_protectedFiles' here, since + // those are protected against unloading. } -bool Resource::isInPakList(const Common::String &filename) { - if (!isAccessable(filename)) - return false; - ResFileMap::iterator iter = _map.find(filename); - if (iter == _map.end()) - return false; - return (iter->_value.type != ResFileEntry::kRaw); +bool Resource::isInPakList(Common::String filename) { + filename.toUppercase(); + return (_archiveFiles->hasArchive(filename) || _protectedFiles->hasArchive(filename)); } void Resource::unloadAllPakFiles() { - // remove all entries - _map.clear(); + _archiveFiles->clear(); + _protectedFiles->clear(); } uint8 *Resource::fileData(const char *file, uint32 *size) { @@ -318,9 +239,7 @@ uint8 *Resource::fileData(const char *file, uint32 *size) { } bool Resource::exists(const char *file, bool errorOutOnFail) { - if (Common::File::exists(file)) - return true; - else if (isAccessable(file)) + if (_files.hasFile(file)) return true; else if (errorOutOnFail) error("File '%s' can't be found", file); @@ -328,21 +247,13 @@ bool Resource::exists(const char *file, bool errorOutOnFail) { } uint32 Resource::getFileSize(const char *file) { - CompFileMap::iterator compEntry; - - if (Common::File::exists(file)) { - Common::File f; - if (f.open(file)) - return f.size(); - } else { - if (!isAccessable(file)) - return 0; + Common::SeekableReadStream *stream = getFileStream(file); + if (!stream) + return 0; - ResFileMap::const_iterator iter = _map.find(file); - if (iter != _map.end()) - return iter->_value.size; - } - return 0; + uint32 size = stream->size(); + delete stream; + return size; } bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) { @@ -351,1181 +262,57 @@ bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) { return false; memset(buf, 0, maxSize); - stream->read(buf, (maxSize <= stream->size()) ? maxSize : stream->size()); + stream->read(buf, ((int32)maxSize <= stream->size()) ? maxSize : stream->size()); delete stream; return true; } Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) { - CompFileMap::iterator compEntry; - - if ((compEntry = _compFiles.find(file)) != _compFiles.end()) - return new Common::MemoryReadStream(compEntry->_value.data, compEntry->_value.size, false); - - if (!isAccessable(file)) - return 0; - - ResFileMap::const_iterator iter = _map.find(file); - if (iter == _map.end()) - return 0; - - if (iter->_value.parent.empty()) { - Common::File *stream = new Common::File(); - if (!stream->open(file)) { - delete stream; - stream = 0; - error("Couldn't open file '%s'", file.c_str()); - } - return stream; - } else { - Common::SeekableReadStream *parent = getFileStream(iter->_value.parent); - assert(parent); - - ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent); - const ResArchiveLoader *loader = getLoader(parentIter->_value.type); - assert(loader); - - return loader->loadFileFromArchive(file, parent, iter->_value); - } - - return 0; -} - -bool Resource::isAccessable(const Common::String &file) { - checkFile(file); - - ResFileMap::const_iterator iter = _map.find(file); - while (iter != _map.end()) { - if (!iter->_value.parent.empty()) { - iter = _map.find(iter->_value.parent); - if (iter != _map.end()) { - // parent can never be a non archive file - if (iter->_value.type == ResFileEntry::kRaw) - return false; - // not mounted parent means not accessable - else if (!iter->_value.mounted) - return false; - } - } else { - return true; - } - } - return false; -} - -void Resource::checkFile(const Common::String &file) { - if (_map.find(file) == _map.end()) { - CompFileMap::const_iterator iter; - - if ((iter = _compFiles.find(file)) != _compFiles.end()) { - ResFileEntry entry; - entry.parent = ""; - entry.size = iter->_value.size; - entry.mounted = false; - entry.preload = false; - entry.prot = false; - entry.type = ResFileEntry::kAutoDetect; - entry.offset = 0; - _map[file] = entry; - - detectFileTypes(); - } else if (Common::File::exists(file)) { - Common::File temp; - if (temp.open(file)) { - ResFileEntry entry; - entry.parent = ""; - entry.size = temp.size(); - entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0; - entry.preload = false; - entry.prot = false; - entry.type = ResFileEntry::kAutoDetect; - entry.offset = 0; - _map[file] = entry; - temp.close(); - - detectFileTypes(); - } - } - } -} - -void Resource::detectFileTypes() { - for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) { - if (!isAccessable(i->_key)) - continue; - - if (i->_value.type == ResFileEntry::kAutoDetect) { - Common::SeekableReadStream *stream = 0; - for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) { - if (!(*l)->checkFilename(i->_key)) - continue; - - if (!stream) - stream = getFileStream(i->_key); - - if ((*l)->isLoadable(i->_key, *stream)) { - i->_value.type = (*l)->getType(); - i->_value.mounted = false; - i->_value.preload = false; - break; - } - } - delete stream; - stream = 0; - - if (i->_value.type == ResFileEntry::kAutoDetect) - i->_value.type = ResFileEntry::kRaw; - } - } -} - -void Resource::tryLoadCompFiles() { - for (CCompLoaderIterator i = _compLoaders.begin(); i != _compLoaders.end(); ++i) { - if ((*i)->checkForFiles()) - (*i)->loadFile(_compFiles); - } -} - -#pragma mark - -#pragma mark - ResFileLodaer -#pragma mark - - -class ResLoaderPak : public ResArchiveLoader { -public: - bool checkFilename(Common::String filename) const; - bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; - bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const; - Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; - - ResFileEntry::kType getType() const { - return ResFileEntry::kPak; - } -}; - -bool ResLoaderPak::checkFilename(Common::String filename) const { - filename.toUppercase(); - return (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK") || filename.hasSuffix(".VRM") || filename.hasSuffix(".TLK") || filename.equalsIgnoreCase(StaticResource::staticDataFilename())); + return _files.openFile(file); } -bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { - uint32 filesize = stream.size(); - uint32 offset = 0; - bool switchEndian = false; - bool firstFile = true; - - offset = stream.readUint32LE(); - if (offset > filesize) { - switchEndian = true; - offset = SWAP_BYTES_32(offset); - } - - Common::String file = ""; - while (!stream.eos()) { - // The start offset of a file should never be in the filelist - if (offset < stream.pos() || offset > filesize) - return false; - - byte c = 0; - - file = ""; - - while (!stream.eos() && (c = stream.readByte()) != 0) - file += c; - - if (stream.eos()) - return false; +Common::ArchivePtr Resource::loadArchive(const Common::String &file) { + ArchiveMap::iterator cachedArchive = _archiveCache.find(file); + if (cachedArchive != _archiveCache.end()) + return cachedArchive->_value; - // Quit now if we encounter an empty string - if (file.empty()) { - if (firstFile) - return false; - else + Common::SeekableReadStream *stream = getFileStream(file); + if (!stream) + return Common::ArchivePtr(); + + Common::ArchivePtr archive; + for (LoaderList::const_iterator i = _loaders.begin(); i != _loaders.end(); ++i) { + if ((*i)->checkFilename(file)) { + if ((*i)->isLoadable(file, *stream)) { + stream->seek(0, SEEK_SET); + archive = Common::ArchivePtr((*i)->load(this, file, *stream)); break; - } - - firstFile = false; - offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); - - if (!offset || offset == filesize) - break; - } - - return true; -} - -namespace { - -Common::String readString(Common::SeekableReadStream &stream) { - Common::String result; - char c = 0; - - while ((c = stream.readByte()) != 0) - result += c; - - return result; -} - -} // end of anonymous namespace - -bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { - uint32 filesize = stream.size(); - - uint32 startoffset = 0, endoffset = 0; - bool switchEndian = false; - bool firstFile = true; - - startoffset = stream.readUint32LE(); - if (startoffset > filesize) { - switchEndian = true; - startoffset = SWAP_BYTES_32(startoffset); - } - - Common::String file = ""; - while (!stream.eos()) { - // The start offset of a file should never be in the filelist - if (startoffset < stream.pos() || startoffset > filesize) { - warning("PAK file '%s' is corrupted", filename.c_str()); - return false; - } - - file = ""; - byte c = 0; - - while (!stream.eos() && (c = stream.readByte()) != 0) - file += c; - - if (stream.eos()) { - warning("PAK file '%s' is corrupted", filename.c_str()); - return false; - } - - // Quit now if we encounter an empty string - if (file.empty()) { - if (firstFile) { - warning("PAK file '%s' is corrupted", filename.c_str()); - return false; } else { - break; - } - } - - firstFile = false; - endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); - - if (!endoffset) - endoffset = filesize; - - if (startoffset != endoffset) { - ResFileEntry entry; - entry.size = endoffset - startoffset; - entry.offset = startoffset; - entry.parent = filename; - entry.type = ResFileEntry::kAutoDetect; - entry.mounted = false; - entry.prot = false; - entry.preload = false; - - files.push_back(File(file, entry)); - } - - if (endoffset == filesize) - break; - - startoffset = endoffset; - } - - FileList::const_iterator iter = Common::find(files.begin(), files.end(), Common::String("LINKLIST")); - if (iter != files.end()) { - stream.seek(iter->entry.offset, SEEK_SET); - - uint32 magic = stream.readUint32BE(); - - if (magic != MKID_BE('SCVM')) - error("LINKLIST file does not contain 'SCVM' header"); - - uint32 links = stream.readUint32BE(); - for (uint i = 0; i < links; ++i) { - Common::String linksTo = readString(stream); - uint32 sources = stream.readUint32BE(); - - iter = Common::find(files.begin(), files.end(), linksTo); - if (iter == files.end()) - error("PAK file link destination '%s' not found", linksTo.c_str()); - - for (uint j = 0; j < sources; ++j) { - Common::String dest = readString(stream); - files.push_back(File(dest, iter->entry)); - // Better safe than sorry, we update the 'iter' value, in case push_back invalidated it - iter = Common::find(files.begin(), files.end(), linksTo); - } - } - } - - return true; -} - -Common::SeekableReadStream *ResLoaderPak::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { - assert(archive); - - archive->seek(entry.offset, SEEK_SET); - Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry.offset, entry.offset + entry.size, true); - assert(stream); - return stream; -} - -class ResLoaderInsMalcolm : public ResArchiveLoader { -public: - bool checkFilename(Common::String filename) const; - bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; - bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const; - Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; - - ResFileEntry::kType getType() const { - return ResFileEntry::kInsMal; - } -}; - -bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const { - filename.toUppercase(); - if (!filename.hasSuffix(".001")) - return false; - return true; -} - -bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { - stream.seek(3); - uint32 size = stream.readUint32LE(); - - if (size+7 > stream.size()) - return false; - - stream.seek(size+5, SEEK_SET); - uint8 buffer[2]; - stream.read(&buffer, 2); - - return (buffer[0] == 0x0D && buffer[1] == 0x0A); -} - -bool ResLoaderInsMalcolm::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { - Common::List<Common::String> filenames; - - // thanks to eriktorbjorn for this code (a bit modified though) - stream.seek(3, SEEK_SET); - - // first file is the index table - uint32 size = stream.readUint32LE(); - Common::String temp = ""; - - for (uint32 i = 0; i < size; ++i) { - byte c = stream.readByte(); - - if (c == '\\') { - temp = ""; - } else if (c == 0x0D) { - // line endings are CRLF - c = stream.readByte(); - assert(c == 0x0A); - ++i; - - filenames.push_back(temp); - } else { - temp += (char)c; - } - } - - stream.seek(3, SEEK_SET); - - for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) { - ResFileEntry entry; - entry.parent = filename; - entry.type = ResFileEntry::kAutoDetect; - entry.mounted = false; - entry.preload = false; - entry.prot = false; - entry.size = stream.readUint32LE(); - entry.offset = stream.pos(); - stream.seek(entry.size, SEEK_CUR); - files.push_back(File(*file, entry)); - } - - return true; -} - -Common::SeekableReadStream *ResLoaderInsMalcolm::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { - assert(archive); - - archive->seek(entry.offset, SEEK_SET); - Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry.offset, entry.offset + entry.size, true); - assert(stream); - return stream; -} - -class ResLoaderTlk : public ResArchiveLoader { -public: - bool checkFilename(Common::String filename) const; - bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; - bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const; - Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const; - - ResFileEntry::kType getType() const { - return ResFileEntry::kTlk; - } - -private: - static bool sortTlkFileList(const File &l, const File &r); - static FileList::const_iterator nextFile(const FileList &list, FileList::const_iterator iter); -}; - -bool ResLoaderTlk::checkFilename(Common::String filename) const { - filename.toUppercase(); - return (filename.hasSuffix(".TLK")); -} - -bool ResLoaderTlk::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { - uint16 entries = stream.readUint16LE(); - uint32 entryTableSize = (entries * 8); - - if (entryTableSize + 2 > stream.size()) - return false; - - uint32 offset = 0; - - for (uint i = 0; i < entries; ++i) { - stream.readUint32LE(); - offset = stream.readUint32LE(); - - if (offset > stream.size()) - return false; - } - - return true; -} - -bool ResLoaderTlk::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const { - uint16 entries = stream.readUint16LE(); - - for (uint i = 0; i < entries; ++i) { - ResFileEntry entry; - entry.parent = filename; - entry.type = ResFileEntry::kAutoDetect; - entry.mounted = false; - entry.preload = false; - entry.prot = false; - - uint32 resFilename = stream.readUint32LE(); - uint32 resOffset = stream.readUint32LE(); - - entry.offset = resOffset+4; - - char realFilename[20]; - snprintf(realFilename, 20, "%.08u.AUD", resFilename); - - uint32 curOffset = stream.pos(); - stream.seek(resOffset, SEEK_SET); - entry.size = stream.readUint32LE(); - stream.seek(curOffset, SEEK_SET); - - files.push_back(FileList::value_type(realFilename, entry)); - } - - return true; -} - -Common::SeekableReadStream *ResLoaderTlk::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const { - assert(archive); - - archive->seek(entry.offset, SEEK_SET); - Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry.offset, entry.offset + entry.size, true); - assert(stream); - return stream; -} - -#pragma mark - -#pragma mark - CompFileLoader -#pragma mark - - -class FileExpanderSource { -public: - FileExpanderSource(const uint8 *data, int dataSize) : _dataPtr(data), _endofBuffer(data + dataSize), _bitsLeft(8), _key(0), _index(0) {} - ~FileExpanderSource() {} - - void advSrcRefresh(); - void advSrcBitsBy1(); - void advSrcBitsByIndex(uint8 newIndex); - - uint8 getKeyLower() { return _key & 0xff; } - void setIndex(uint8 index) { _index = index; } - uint16 getKeyMasked(uint8 newIndex); - uint16 keyMaskedAlign(uint16 val); - - void copyBytes(uint8 *& dst); - -private: - const uint8 *_dataPtr; - const uint8 *_endofBuffer; - uint16 _key; - int8 _bitsLeft; - uint8 _index; -}; - -void FileExpanderSource::advSrcBitsBy1() { - _key >>= 1; - if (!--_bitsLeft) { - if (_dataPtr < _endofBuffer) - _key = ((*_dataPtr++) << 8 ) | (_key & 0xff); - _bitsLeft = 8; - } -} - -void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) { - _index = newIndex; - _bitsLeft -= _index; - if (_bitsLeft <= 0) { - _key >>= (_index + _bitsLeft); - _index = -_bitsLeft; - _bitsLeft = 8 - _index; - if (_dataPtr < _endofBuffer) - _key = (*_dataPtr++ << 8) | (_key & 0xff); - } - _key >>= _index; -} - -uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) { - static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; - _index = newIndex; - uint16 res = 0; - - if (_index > 8) { - newIndex = _index - 8; - res = (_key & 0xff) & mskTable[8]; - advSrcBitsByIndex(8); - _index = newIndex; - res |= (((_key & 0xff) & mskTable[_index]) << 8); - advSrcBitsByIndex(_index); - } else { - res = (_key & 0xff) & mskTable[_index]; - advSrcBitsByIndex(_index); - } - - return res; -} - -void FileExpanderSource::copyBytes(uint8 *& dst) { - advSrcBitsByIndex(_bitsLeft); - uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1; - _dataPtr += 2; - - if (r) - error("decompression failure"); - - memcpy(dst, _dataPtr, _key); - _dataPtr += _key; - dst += _key; -} - -uint16 FileExpanderSource::keyMaskedAlign(uint16 val) { - val -= 0x101; - _index = (val & 0xff) >> 2; - int16 b = ((_bitsLeft << 8) | _index) - 1; - _bitsLeft = b >> 8; - _index = b & 0xff; - uint16 res = (((val & 3) + 4) << _index) + 0x101; - return res + getKeyMasked(_index); -} - -void FileExpanderSource::advSrcRefresh() { - _key = READ_LE_UINT16(_dataPtr); - if (_dataPtr < _endofBuffer - 1) - _dataPtr += 2; - _bitsLeft = 8; -} - -class FileExpander { -public: - FileExpander(); - ~FileExpander(); - - bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize); - -private: - void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt); - uint8 calcCmdAndIndex(const uint8 *tbl, int16 ¶); - - FileExpanderSource *_src; - uint8 *_tables[9]; - uint16 *_tables16[3]; -}; - -FileExpander::FileExpander() : _src(0) { - _tables[0] = new uint8[3914]; - assert(_tables[0]); - - _tables[1] = _tables[0] + 320; - _tables[2] = _tables[0] + 352; - _tables[3] = _tables[0] + 864; - _tables[4] = _tables[0] + 2016; - _tables[5] = _tables[0] + 2528; - _tables[6] = _tables[0] + 2656; - _tables[7] = _tables[0] + 2736; - _tables[8] = _tables[0] + 2756; - - _tables16[0] = (uint16 *)(_tables[0] + 3268); - _tables16[1] = (uint16 *)(_tables[0] + 3302); - _tables16[2] = (uint16 *)(_tables[0] + 3338); -} - -FileExpander::~FileExpander() { - delete _src; - delete[] _tables[0]; -} - -bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) { - static const uint8 indexTable[] = { - 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A, - 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F - }; - - memset(_tables[0], 0, 3914); - - uint8 *d = dst; - uint16 tableSize0 = 0; - uint16 tableSize1 = 0; - bool needrefresh = true; - bool postprocess = false; - - _src = new FileExpanderSource(src, compressedSize); - - while (d < dst + outsize) { - - if (needrefresh) { - needrefresh = false; - _src->advSrcRefresh(); - } - - _src->advSrcBitsBy1(); - - int mode = _src->getKeyMasked(2) - 1; - if (mode == 1) { - tableSize0 = _src->getKeyMasked(5) + 257; - tableSize1 = _src->getKeyMasked(5) + 1; - memset(_tables[7], 0, 19); - - const uint8 *itbl = indexTable; - int numbytes = _src->getKeyMasked(4) + 4; - - while (numbytes--) - _tables[7][*itbl++] = _src->getKeyMasked(3); - - generateTables(7, 8, 255, 19); - - int cnt = tableSize0 + tableSize1; - uint8 *tmp = _tables[0]; - - while (cnt) { - uint16 cmd = _src->getKeyLower(); - cmd = READ_LE_UINT16(&_tables[8][cmd << 1]); - _src->advSrcBitsByIndex(_tables[7][cmd]); - - if (cmd < 16) { - *tmp++ = cmd; - cnt--; - } else { - uint8 tmpI = 0; - if (cmd == 16) { - cmd = _src->getKeyMasked(2) + 3; - tmpI = *(tmp - 1); - } else if (cmd == 17) { - cmd = _src->getKeyMasked(3) + 3; - } else { - cmd = _src->getKeyMasked(7) + 11; - } - _src->setIndex(tmpI); - memset(tmp, tmpI, cmd); - tmp += cmd; - - cnt -= cmd; - if (cnt < 0) - error("decompression failure"); - } + stream->seek(0, SEEK_SET); } - - memcpy(_tables[1], _tables[0] + tableSize0, tableSize1); - generateTables(0, 2, 3, tableSize0); - generateTables(1, 4, 5, tableSize1); - postprocess = true; - } else if (mode < 0) { - _src->copyBytes(d); - postprocess = false; - needrefresh = true; - } else if (mode == 0){ - uint8 *d2 = _tables[0]; - memset(d2, 8, 144); - memset(d2 + 144, 9, 112); - memset(d2 + 256, 7, 24); - memset(d2 + 280, 8, 8); - d2 = _tables[1]; - memset(d2, 5, 32); - tableSize0 = 288; - tableSize1 = 32; - - generateTables(0, 2, 3, tableSize0); - generateTables(1, 4, 5, tableSize1); - postprocess = true; - } else { - error("decompression failure"); } - - if (!postprocess) - continue; - - int16 cmd = 0; - - do { - cmd = ((int16*) _tables[2])[_src->getKeyLower()]; - _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]); - - if (cmd == 0x11d) { - cmd = 0x200; - } else if (cmd > 0x108) { - cmd = _src->keyMaskedAlign(cmd); - } - - if (!(cmd >> 8)) { - *d++ = cmd & 0xff; - } else if (cmd != 0x100) { - cmd -= 0xfe; - int16 offset = ((int16*) _tables[4])[_src->getKeyLower()]; - _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]); - if ((offset & 0xff) >= 4) { - uint8 newIndex = ((offset & 0xff) >> 1) - 1; - offset = (((offset & 1) + 2) << newIndex); - offset += _src->getKeyMasked(newIndex); - } - - uint8 *s2 = d - 1 - offset; - if (s2 >= dst) { - while (cmd--) - *d++ = *s2++; - } else { - uint32 pos = dst - s2; - s2 += (d - dst); - - if (pos < (uint32) cmd) { - cmd -= pos; - while (pos--) - *d++ = *s2++; - s2 = dst; - } - while (cmd--) - *d++ = *s2++; - } - } - } while (cmd != 0x100); } - delete _src; - _src = 0; - - return true; -} - -void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) { - const uint8 *tbl1 = _tables[srcIndex]; - uint8 *tbl2 = _tables[dstIndex]; - const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2]; - - if (!cnt) - return; - - const uint8 *s = tbl1; - memset(_tables16[0], 0, 32); - - for (int i = 0; i < cnt; i++) - _tables16[0][(*s++)]++; - - _tables16[1][1] = 0; - - for (uint16 i = 1, r = 0; i < 16; i++) { - r = (r + _tables16[0][i]) << 1; - _tables16[1][i + 1] = r; - } - - if (_tables16[1][16]) { - uint16 r = 0; - for (uint16 i = 1; i < 16; i++) - r += _tables16[0][i]; - if (r > 1) - error("decompression failure"); - } - - s = tbl1; - uint16 *d = _tables16[2]; - for (int i = 0; i < cnt; i++) { - uint16 t = *s++; - if (t) { - _tables16[1][t]++; - t = _tables16[1][t] - 1; - } - *d++ = t; - } - - s = tbl1; - d = _tables16[2]; - for (int i = 0; i < cnt; i++) { - int8 t = ((int8)(*s++)) - 1; - if (t > 0) { - uint16 v1 = *d; - uint16 v2 = 0; - - do { - v2 = (v2 << 1) | (v1 & 1); - v1 >>= 1; - } while (--t && v1); - - t++; - uint8 c1 = (v1 & 1); - while (t--) { - uint8 c2 = v2 >> 15; - v2 = (v2 << 1) | c1; - c1 = c2; - }; - - *d++ = v2; - } else { - d++; - } - } - - memset(tbl2, 0, 512); - - cnt--; - s = tbl1 + cnt; - d = &_tables16[2][cnt]; - uint16 * bt = (uint16*) tbl3; - uint16 inc = 0; - uint16 cnt2 = 0; - - do { - uint8 t = *s--; - uint16 *s2 = (uint16*) tbl2; - - if (t && t < 9) { - inc = 1 << t; - uint16 o = *d; - - do { - s2[o] = cnt; - o += inc; - } while (!(o & 0xf00)); - - } else if (t > 8) { - if (!bt) - error("decompression failure"); - - t -= 8; - uint8 shiftCnt = 1; - uint8 v = (*d) >> 8; - s2 = &((uint16*) tbl2)[*d & 0xff]; - - do { - if (!*s2) { - *s2 = (uint16)(~cnt2); - *(uint32*)&bt[cnt2] = 0; - cnt2 += 2; - } - - s2 = &bt[(uint16)(~*s2)]; - if (v & shiftCnt) - s2++; - - shiftCnt <<= 1; - } while (--t); - *s2 = cnt; - } - d--; - } while (--cnt >= 0); -} - -uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 ¶) { - const uint16 *t = (const uint16*)tbl; - _src->advSrcBitsByIndex(8); - uint8 newIndex = 0; - uint16 v = _src->getKeyLower(); - - do { - newIndex++; - para = t[((~para) & 0xfffe) | (v & 1)]; - v >>= 1; - } while (para < 0); - - return newIndex; -} - -class CompLoaderInsHof : public CompArchiveLoader { -public: - CompLoaderInsHof() { - _fileExtP = "%03d"; - _checkFile1 = "WESTWOOD.001"; - _checkFile2 = "WESTWOOD.002"; - _containerOffset = 6; - } + delete stream; - virtual bool checkForFiles() const; - virtual bool loadFile(CompFileMap &loadTo) const; - -protected: - struct Archive { - Common::String filename; - uint32 firstFile; - uint32 startOffset; - uint32 lastFile; - uint32 endOffset; - uint32 totalSize; - }; - - const char *_fileExtP; - const char *_checkFile1; - const char *_checkFile2; - uint8 _containerOffset; -}; - -class CompLoaderInsLol : public CompLoaderInsHof { -public: - CompLoaderInsLol() { - _fileExtP = "%d"; - _checkFile1 = "WESTWOOD.1"; - _checkFile2 = "WESTWOOD.2"; - _containerOffset = 0; - } -}; + if (!archive) + return Common::ArchivePtr(); -bool CompLoaderInsHof::checkForFiles() const { - return (Common::File::exists(_checkFile1) && Common::File::exists(_checkFile2)); + _archiveCache[file] = archive; + return archive; } -bool CompLoaderInsHof::loadFile(CompFileMap &loadTo) const { - Common::File tmpFile; - - uint32 pos = 0; - uint32 bytesleft = 0; - bool startFile = true; - - Common::String filenameBase = "WESTWOOD."; - Common::String filenameTemp; - char filenameExt[4]; - - while (filenameBase.lastChar() != '.') - filenameBase.deleteLastChar(); - - Archive newArchive; - - Common::List<Archive> archives; - - for (int8 currentFile = 1; currentFile; currentFile++) { - sprintf(filenameExt, _fileExtP, currentFile); - filenameTemp = filenameBase + Common::String(filenameExt); - - if (!tmpFile.open(filenameTemp)) { - debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); - break; - } - - tmpFile.seek(pos); - uint8 fileId = tmpFile.readByte(); - pos++; - - uint32 size = tmpFile.size() - 1; - if (startFile) { - size -= 4; - if (fileId == currentFile) { - size -= _containerOffset; - pos += _containerOffset; - tmpFile.seek(_containerOffset, SEEK_CUR); - } else { - size = size + 1 - pos; - } - newArchive.filename = filenameBase; - bytesleft = newArchive.totalSize = tmpFile.readUint32LE(); - pos += 4; - newArchive.firstFile = currentFile; - newArchive.startOffset = pos; - startFile = false; - } - - uint32 cs = MIN(size, bytesleft); - bytesleft -= cs; - - tmpFile.close(); - - pos += cs; - if (cs == size) { - if (!bytesleft) { - newArchive.lastFile = currentFile; - newArchive.endOffset = --pos; - archives.push_back(newArchive); - currentFile = -1; - } else { - pos = 0; - } - } else { - startFile = true; - bytesleft = size - cs; - newArchive.lastFile = currentFile--; - newArchive.endOffset = --pos; - archives.push_back(newArchive); - } - } +Common::ArchivePtr Resource::loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset) { + ArchiveMap::iterator cachedArchive = _archiveCache.find(file); + if (cachedArchive != _archiveCache.end()) + return cachedArchive->_value; - FileExpander exp; - CompFileEntry newEntry; - uint32 insize = 0; - uint32 outsize = 0; - uint8 *inbuffer = 0; - uint8 *outbuffer = 0; - uint32 inPart1 = 0; - uint32 inPart2 = 0; - uint8 compressionType = 0; - Common::String entryStr; - - pos = 0; - - const uint32 kExecSize = 0x0bba; - const uint32 kHeaderSize = 30; - const uint32 kHeaderSize2 = 46; - - for (Common::List<Archive>::iterator a = archives.begin(); a != archives.end(); ++a) { - startFile = true; - for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) { - sprintf(filenameExt, _fileExtP, i); - filenameTemp = a->filename + Common::String(filenameExt); - - if (!tmpFile.open(filenameTemp)) { - debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); - break; - } - - uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile.size(); - - if (startFile) { - startFile = false; - pos = a->startOffset + kExecSize; - if (pos > size) { - pos -= size; - tmpFile.close(); - continue; - } - } else { - if (inPart2) { - tmpFile.seek(1); - tmpFile.read(inbuffer + inPart1, inPart2); - inPart2 = 0; - - if (compressionType > 0) - exp.process(outbuffer, inbuffer, outsize, insize); - else - memcpy(outbuffer, inbuffer, outsize); - - delete[] inbuffer; - inbuffer = 0; - newEntry.data = outbuffer; - newEntry.size = outsize; - loadTo[entryStr] = newEntry; - } - pos++; - } + Common::ArchivePtr archive(InstallerLoader::load(this, file, ext, offset)); + if (!archive) + return Common::ArchivePtr(); - while (pos < size) { - uint8 hdr[43]; - uint32 m = 0; - tmpFile.seek(pos); - - if (pos + 42 > size) { - m = size - pos; - uint32 b = 42 - m; - - if (m >= 4) { - uint32 id = tmpFile.readUint32LE(); - if (id == 0x06054B50) { - startFile = true; - break; - } else { - tmpFile.seek(pos); - } - } - - sprintf(filenameExt, _fileExtP, i + 1); - filenameTemp = a->filename + Common::String(filenameExt); - - Common::File tmpFile2; - tmpFile2.open(filenameTemp); - tmpFile.read(hdr, m); - tmpFile2.read(hdr + m, b); - tmpFile2.close(); - - } else { - tmpFile.read(hdr, 42); - } - - uint32 id = READ_LE_UINT32(hdr); - - if (id == 0x04034B50) { - compressionType = hdr[8]; - insize = READ_LE_UINT32(hdr + 18); - outsize = READ_LE_UINT32(hdr + 22); - - uint16 filestrlen = READ_LE_UINT16(hdr + 26); - *(hdr + 30 + filestrlen) = 0; - entryStr = Common::String((const char *)(hdr + 30)); - pos += (kHeaderSize + filestrlen - m); - tmpFile.seek(pos); - - outbuffer = new uint8[outsize]; - if (!outbuffer) - error("Out of memory: Can't uncompress installer files"); - - if (!inbuffer) { - inbuffer = new uint8[insize]; - if (!inbuffer) - error("Out of memory: Can't uncompress installer files"); - } - - if ((pos + insize) > size) { - // this is for files that are split between two archive files - inPart1 = size - pos; - inPart2 = insize - inPart1; - tmpFile.read(inbuffer, inPart1); - } else { - tmpFile.read(inbuffer, insize); - inPart2 = 0; - - if (compressionType > 0) - exp.process(outbuffer, inbuffer, outsize, insize); - else - memcpy(outbuffer, inbuffer, outsize); - - delete[] inbuffer; - inbuffer = 0; - newEntry.data = outbuffer; - newEntry.size = outsize; - loadTo[entryStr] = newEntry; - } - - pos += insize; - if (pos > size) { - pos -= size; - break; - } - } else { - uint32 filestrlen = READ_LE_UINT32(hdr + 28); - pos += (kHeaderSize2 + filestrlen - m); - } - } - tmpFile.close(); - } - } - - archives.clear(); - return true; + _archiveCache[file] = archive; + return archive; } #pragma mark - @@ -1534,17 +321,6 @@ void Resource::initializeLoaders() { _loaders.push_back(LoaderList::value_type(new ResLoaderPak())); _loaders.push_back(LoaderList::value_type(new ResLoaderInsMalcolm())); _loaders.push_back(LoaderList::value_type(new ResLoaderTlk())); - - _compLoaders.push_back(CompLoaderList::value_type(new CompLoaderInsHof())); - _compLoaders.push_back(CompLoaderList::value_type(new CompLoaderInsLol())); -} - -const ResArchiveLoader *Resource::getLoader(ResFileEntry::kType type) const { - for (CLoaderIterator i = _loaders.begin(); i != _loaders.end(); ++i) { - if ((*i)->getType() == type) - return (*i).get(); - } - return 0; } } // end of namespace Kyra diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index d43f730e6b..799068d158 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -35,74 +35,16 @@ #include "common/hashmap.h" #include "common/stream.h" #include "common/ptr.h" +#include "common/archive.h" #include "kyra/kyra_v1.h" #include "kyra/kyra_hof.h" namespace Kyra { -struct ResFileEntry { - Common::String parent; - uint32 size; - - bool preload; - bool mounted; - bool prot; - - enum kType { - kRaw = 0, - kPak = 1, - kInsMal = 2, - kTlk = 3, - kAutoDetect - }; - kType type; - uint32 offset; -}; - -struct CompFileEntry { - uint32 size; - uint8 *data; -}; - -typedef Common::HashMap<Common::String, ResFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ResFileMap; -typedef Common::HashMap<Common::String, CompFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> CompFileMap; class Resource; -class ResArchiveLoader { -public: - struct File { - File() : filename(), entry() {} - File(const Common::String &f, const ResFileEntry &e) : filename(f), entry(e) {} - - bool operator ==(const Common::String &r) const { - return filename.equalsIgnoreCase(r); - } - - Common::String filename; - ResFileEntry entry; - }; - typedef Common::List<File> FileList; - - virtual ~ResArchiveLoader() {} - - virtual bool checkFilename(Common::String filename) const = 0; - virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0; - virtual bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const = 0; - // parameter 'archive' can be deleted by this method and it may not be deleted from the caller - virtual Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const = 0; - - virtual ResFileEntry::kType getType() const = 0; -protected: -}; - -class CompArchiveLoader { -public: - virtual ~CompArchiveLoader() {} - - virtual bool checkForFiles() const = 0; - virtual bool loadFile(CompFileMap &loadTo) const = 0; -}; +class ResArchiveLoader; class Resource { public: @@ -111,9 +53,9 @@ public: bool reset(); - bool loadPakFile(const Common::String &filename); - void unloadPakFile(const Common::String &filename); - bool isInPakList(const Common::String &filename); + bool loadPakFile(Common::String filename); + void unloadPakFile(Common::String filename); + bool isInPakList(Common::String filename); bool loadFileList(const Common::String &filedata); bool loadFileList(const char * const *filelist, uint32 numFiles); @@ -127,27 +69,20 @@ public: bool loadFileToBuf(const char *file, void *buf, uint32 maxSize); protected: - void checkFile(const Common::String &file); - bool isAccessable(const Common::String &file); + typedef Common::HashMap<Common::String, Common::ArchivePtr, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> ArchiveMap; + ArchiveMap _archiveCache; + + Common::SearchSet _files; + Common::SharedPtr<Common::SearchSet> _archiveFiles; + Common::SharedPtr<Common::SearchSet> _protectedFiles; - void detectFileTypes(); + Common::ArchivePtr loadArchive(const Common::String &file); + Common::ArchivePtr loadInstallerArchive(const Common::String &file, const Common::String &ext, const uint8 offset); void initializeLoaders(); - const ResArchiveLoader *getLoader(ResFileEntry::kType type) const; + typedef Common::List<Common::SharedPtr<ResArchiveLoader> > LoaderList; - typedef LoaderList::iterator LoaderIterator; - typedef LoaderList::const_iterator CLoaderIterator; LoaderList _loaders; - ResFileMap _map; - - typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList; - typedef CompLoaderList::iterator CompLoaderIterator; - typedef CompLoaderList::const_iterator CCompLoaderIterator; - CompLoaderList _compLoaders; - CompFileMap _compFiles; - - void tryLoadCompFiles(); - void clearCompFileList(); KyraEngine_v1 *_vm; }; @@ -277,7 +212,7 @@ public: StaticResource(KyraEngine_v1 *vm) : _vm(vm), _resList(), _fileLoader(0), _builtIn(0), _filenameTable(0) {} ~StaticResource() { deinit(); } - static bool checkKyraDat(); + static bool checkKyraDat(Resource *res); bool init(); void deinit(); @@ -332,7 +267,7 @@ private: void freeHofShapeAnimDataV2(void *&ptr, int &size); const char *getFilename(const char *name); - uint8 *getFile(const char *name, int &size); + Common::SeekableReadStream *getFile(const char *name); enum kResTypes { kLanguageList, diff --git a/engines/kyra/resource_intern.cpp b/engines/kyra/resource_intern.cpp new file mode 100644 index 0000000000..f97319a43a --- /dev/null +++ b/engines/kyra/resource_intern.cpp @@ -0,0 +1,1072 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "kyra/resource_intern.h" +#include "kyra/resource.h" + +#include "common/stream.h" +#include "common/endian.h" + +namespace Kyra { + +// Implementation of various Archive subclasses + +// -> PlainArchive implementation + +PlainArchive::PlainArchive(Resource *owner, const Common::String &filename, const FileInputList &files) + : _owner(owner), _filename(filename), _files() { + for (FileInputList::iterator i = files.begin(); i != files.end(); ++i) { + Entry entry; + + entry.offset = i->offset; + entry.size = i->size; + + _files[i->name] = entry; + } +} + +bool PlainArchive::hasFile(const Common::String &name) { + return (_files.find(name) != _files.end()); +} + +int PlainArchive::getAllNames(Common::StringList &list) { + int count = 0; + + for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) { + list.push_back(i->_key); + ++count; + } + + return count; +} + +Common::SeekableReadStream *PlainArchive::openFile(const Common::String &name) { + FileMap::const_iterator fDesc = _files.find(name); + if (fDesc == _files.end()) + return 0; + + Common::SeekableReadStream *parent = _owner->getFileStream(_filename); + if (!parent) + return 0; + + return new Common::SeekableSubReadStream(parent, fDesc->_value.offset, fDesc->_value.offset + fDesc->_value.size, true); +} + +// -> CachedArchive implementation + +CachedArchive::CachedArchive(const FileInputList &files) + : _files() { + for (FileInputList::iterator i = files.begin(); i != files.end(); ++i) { + Entry entry; + + entry.data = i->data; + entry.size = i->size; + + _files[i->name] = entry; + } +} + +CachedArchive::~CachedArchive() { + for (FileMap::iterator i = _files.begin(); i != _files.end(); ++i) + delete[] i->_value.data; + _files.clear(); +} + +bool CachedArchive::hasFile(const Common::String &name) { + return (_files.find(name) != _files.end()); +} + +int CachedArchive::getAllNames(Common::StringList &list) { + int count = 0; + + for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) { + list.push_back(i->_key); + ++count; + } + + return count; +} + +Common::SeekableReadStream *CachedArchive::openFile(const Common::String &name) { + FileMap::const_iterator fDesc = _files.find(name); + if (fDesc == _files.end()) + return 0; + + return new Common::MemoryReadStream(fDesc->_value.data, fDesc->_value.size, false); +} + +// ResFileLoader implementations + +// -> ResLoaderPak implementation + +bool ResLoaderPak::checkFilename(Common::String filename) const { + filename.toUppercase(); + return (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK") || filename.hasSuffix(".VRM") || filename.hasSuffix(".TLK") || filename.equalsIgnoreCase(StaticResource::staticDataFilename())); +} + +bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { + int32 filesize = stream.size(); + int32 offset = 0; + bool switchEndian = false; + bool firstFile = true; + + offset = stream.readUint32LE(); + if (offset > filesize) { + switchEndian = true; + offset = SWAP_BYTES_32(offset); + } + + Common::String file; + while (!stream.eos()) { + // The start offset of a file should never be in the filelist + if (offset < stream.pos() || offset > filesize) + return false; + + byte c = 0; + + file.clear(); + + while (!stream.eos() && (c = stream.readByte()) != 0) + file += c; + + if (stream.eos()) + return false; + + // Quit now if we encounter an empty string + if (file.empty()) { + if (firstFile) + return false; + else + break; + } + + firstFile = false; + offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); + + if (!offset || offset == filesize) + break; + } + + return true; +} + +namespace { + +Common::String readString(Common::SeekableReadStream &stream) { + Common::String result; + char c = 0; + + while ((c = stream.readByte()) != 0) + result += c; + + return result; +} + +struct PlainArchiveListSearch { + PlainArchiveListSearch(const Common::String &search) : _search(search) {} + + bool operator()(const PlainArchive::InputEntry &entry) { + return _search.equalsIgnoreCase(entry.name); + } + Common::String _search; +}; + +} // end of anonymous namespace + +Common::Archive *ResLoaderPak::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { + int32 filesize = stream.size(); + + int32 startoffset = 0, endoffset = 0; + bool switchEndian = false; + bool firstFile = true; + + startoffset = stream.readUint32LE(); + if (startoffset > filesize) { + switchEndian = true; + startoffset = SWAP_BYTES_32(startoffset); + } + + PlainArchive::FileInputList files; + + Common::String file; + while (!stream.eos()) { + // The start offset of a file should never be in the filelist + if (startoffset < stream.pos() || startoffset > filesize) { + warning("PAK file '%s' is corrupted", filename.c_str()); + return false; + } + + file.clear(); + byte c = 0; + + while (!stream.eos() && (c = stream.readByte()) != 0) + file += c; + + if (stream.eos()) { + warning("PAK file '%s' is corrupted", filename.c_str()); + return false; + } + + // Quit now if we encounter an empty string + if (file.empty()) { + if (firstFile) { + warning("PAK file '%s' is corrupted", filename.c_str()); + return false; + } else { + break; + } + } + + firstFile = false; + endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); + + if (!endoffset) + endoffset = filesize; + + if (startoffset != endoffset) { + PlainArchive::InputEntry entry; + entry.size = endoffset - startoffset; + entry.offset = startoffset; + entry.name = file; + + files.push_back(entry); + } + + if (endoffset == filesize) + break; + + startoffset = endoffset; + } + + PlainArchive::FileInputList::const_iterator iter = Common::find_if(files.begin(), files.end(), PlainArchiveListSearch("LINKLIST")); + if (iter != files.end()) { + stream.seek(iter->offset, SEEK_SET); + + uint32 magic = stream.readUint32BE(); + + if (magic != MKID_BE('SCVM')) + error("LINKLIST file does not contain 'SCVM' header"); + + uint32 links = stream.readUint32BE(); + for (uint i = 0; i < links; ++i) { + Common::String linksTo = readString(stream); + uint32 sources = stream.readUint32BE(); + + iter = Common::find_if(files.begin(), files.end(), PlainArchiveListSearch(linksTo)); + if (iter == files.end()) + error("PAK file link destination '%s' not found", linksTo.c_str()); + + for (uint j = 0; j < sources; ++j) { + Common::String dest = readString(stream); + files.push_back(*iter); + // Better safe than sorry, we update the 'iter' value, in case push_back invalidated it + iter = Common::find_if(files.begin(), files.end(), PlainArchiveListSearch(linksTo)); + } + } + } + + return new PlainArchive(owner, filename, files); +} + +// -> ResLoaderInsMalcolm implementation + +bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const { + filename.toUppercase(); + if (!filename.hasSuffix(".001")) + return false; + return true; +} + +bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { + stream.seek(3, SEEK_SET); + int32 size = stream.readUint32LE(); + + if (size+7 > stream.size()) + return false; + + stream.seek(size+5, SEEK_SET); + uint8 buffer[2]; + stream.read(&buffer, 2); + + return (buffer[0] == 0x0D && buffer[1] == 0x0A); +} + +Common::Archive *ResLoaderInsMalcolm::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { + Common::List<Common::String> filenames; + PlainArchive::FileInputList files; + + // thanks to eriktorbjorn for this code (a bit modified though) + stream.seek(3, SEEK_SET); + + // first file is the index table + uint32 size = stream.readUint32LE(); + Common::String temp; + + for (uint32 i = 0; i < size; ++i) { + byte c = stream.readByte(); + + if (c == '\\') { + temp.clear(); + } else if (c == 0x0D) { + // line endings are CRLF + c = stream.readByte(); + assert(c == 0x0A); + ++i; + + filenames.push_back(temp); + } else { + temp += (char)c; + } + } + + stream.seek(3, SEEK_SET); + + for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) { + PlainArchive::InputEntry entry; + entry.size = stream.readUint32LE(); + entry.offset = stream.pos(); + entry.name = *file; + stream.seek(entry.size, SEEK_CUR); + + files.push_back(entry); + } + + return new PlainArchive(owner, filename, files); +} + +bool ResLoaderTlk::checkFilename(Common::String filename) const { + filename.toUppercase(); + return (filename.hasSuffix(".TLK")); +} + +bool ResLoaderTlk::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { + uint16 entries = stream.readUint16LE(); + int32 entryTableSize = (entries * 8); + + if (entryTableSize + 2 > stream.size()) + return false; + + int32 offset = 0; + + for (uint i = 0; i < entries; ++i) { + stream.readUint32LE(); + offset = stream.readUint32LE(); + + if (offset > stream.size()) + return false; + } + + return true; +} + +Common::Archive *ResLoaderTlk::load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const { + uint16 entries = stream.readUint16LE(); + PlainArchive::FileInputList files; + + for (uint i = 0; i < entries; ++i) { + PlainArchive::InputEntry entry; + + uint32 resFilename = stream.readUint32LE(); + uint32 resOffset = stream.readUint32LE(); + + entry.offset = resOffset+4; + + char realFilename[20]; + snprintf(realFilename, 20, "%.08u.AUD", resFilename); + entry.name = realFilename; + + uint32 curOffset = stream.pos(); + stream.seek(resOffset, SEEK_SET); + entry.size = stream.readUint32LE(); + stream.seek(curOffset, SEEK_SET); + + files.push_back(entry); + } + + return new PlainArchive(owner, filename, files); +} + +// InstallerLoader implementation + +class FileExpanderSource { +public: + FileExpanderSource(const uint8 *data, int dataSize) : _dataPtr(data), _endofBuffer(data + dataSize), _bitsLeft(8), _key(0), _index(0) {} + ~FileExpanderSource() {} + + void advSrcRefresh(); + void advSrcBitsBy1(); + void advSrcBitsByIndex(uint8 newIndex); + + uint8 getKeyLower() { return _key & 0xff; } + void setIndex(uint8 index) { _index = index; } + uint16 getKeyMasked(uint8 newIndex); + uint16 keyMaskedAlign(uint16 val); + + void copyBytes(uint8 *& dst); + +private: + const uint8 *_dataPtr; + const uint8 *_endofBuffer; + uint16 _key; + int8 _bitsLeft; + uint8 _index; +}; + +void FileExpanderSource::advSrcBitsBy1() { + _key >>= 1; + if (!--_bitsLeft) { + if (_dataPtr < _endofBuffer) + _key = ((*_dataPtr++) << 8 ) | (_key & 0xff); + _bitsLeft = 8; + } +} + +void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) { + _index = newIndex; + _bitsLeft -= _index; + if (_bitsLeft <= 0) { + _key >>= (_index + _bitsLeft); + _index = -_bitsLeft; + _bitsLeft = 8 - _index; + if (_dataPtr < _endofBuffer) + _key = (*_dataPtr++ << 8) | (_key & 0xff); + } + _key >>= _index; +} + +uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) { + static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF }; + _index = newIndex; + uint16 res = 0; + + if (_index > 8) { + newIndex = _index - 8; + res = (_key & 0xff) & mskTable[8]; + advSrcBitsByIndex(8); + _index = newIndex; + res |= (((_key & 0xff) & mskTable[_index]) << 8); + advSrcBitsByIndex(_index); + } else { + res = (_key & 0xff) & mskTable[_index]; + advSrcBitsByIndex(_index); + } + + return res; +} + +void FileExpanderSource::copyBytes(uint8 *& dst) { + advSrcBitsByIndex(_bitsLeft); + uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1; + _dataPtr += 2; + + if (r) + error("decompression failure"); + + memcpy(dst, _dataPtr, _key); + _dataPtr += _key; + dst += _key; +} + +uint16 FileExpanderSource::keyMaskedAlign(uint16 val) { + val -= 0x101; + _index = (val & 0xff) >> 2; + int16 b = ((_bitsLeft << 8) | _index) - 1; + _bitsLeft = b >> 8; + _index = b & 0xff; + uint16 res = (((val & 3) + 4) << _index) + 0x101; + return res + getKeyMasked(_index); +} + +void FileExpanderSource::advSrcRefresh() { + _key = READ_LE_UINT16(_dataPtr); + if (_dataPtr < _endofBuffer - 1) + _dataPtr += 2; + _bitsLeft = 8; +} + +class FileExpander { +public: + FileExpander(); + ~FileExpander(); + + bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize); + +private: + void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt); + uint8 calcCmdAndIndex(const uint8 *tbl, int16 ¶); + + FileExpanderSource *_src; + uint8 *_tables[9]; + uint16 *_tables16[3]; +}; + +FileExpander::FileExpander() : _src(0) { + _tables[0] = new uint8[3914]; + assert(_tables[0]); + + _tables[1] = _tables[0] + 320; + _tables[2] = _tables[0] + 352; + _tables[3] = _tables[0] + 864; + _tables[4] = _tables[0] + 2016; + _tables[5] = _tables[0] + 2528; + _tables[6] = _tables[0] + 2656; + _tables[7] = _tables[0] + 2736; + _tables[8] = _tables[0] + 2756; + + _tables16[0] = (uint16 *)(_tables[0] + 3268); + _tables16[1] = (uint16 *)(_tables[0] + 3302); + _tables16[2] = (uint16 *)(_tables[0] + 3338); +} + +FileExpander::~FileExpander() { + delete _src; + delete[] _tables[0]; +} + +bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) { + static const uint8 indexTable[] = { + 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A, + 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F + }; + + memset(_tables[0], 0, 3914); + + uint8 *d = dst; + uint16 tableSize0 = 0; + uint16 tableSize1 = 0; + bool needrefresh = true; + bool postprocess = false; + + _src = new FileExpanderSource(src, compressedSize); + + while (d < dst + outsize) { + + if (needrefresh) { + needrefresh = false; + _src->advSrcRefresh(); + } + + _src->advSrcBitsBy1(); + + int mode = _src->getKeyMasked(2) - 1; + if (mode == 1) { + tableSize0 = _src->getKeyMasked(5) + 257; + tableSize1 = _src->getKeyMasked(5) + 1; + memset(_tables[7], 0, 19); + + const uint8 *itbl = indexTable; + int numbytes = _src->getKeyMasked(4) + 4; + + while (numbytes--) + _tables[7][*itbl++] = _src->getKeyMasked(3); + + generateTables(7, 8, 255, 19); + + int cnt = tableSize0 + tableSize1; + uint8 *tmp = _tables[0]; + + while (cnt) { + uint16 cmd = _src->getKeyLower(); + cmd = READ_LE_UINT16(&_tables[8][cmd << 1]); + _src->advSrcBitsByIndex(_tables[7][cmd]); + + if (cmd < 16) { + *tmp++ = cmd; + cnt--; + } else { + uint8 tmpI = 0; + if (cmd == 16) { + cmd = _src->getKeyMasked(2) + 3; + tmpI = *(tmp - 1); + } else if (cmd == 17) { + cmd = _src->getKeyMasked(3) + 3; + } else { + cmd = _src->getKeyMasked(7) + 11; + } + _src->setIndex(tmpI); + memset(tmp, tmpI, cmd); + tmp += cmd; + + cnt -= cmd; + if (cnt < 0) + error("decompression failure"); + } + } + + memcpy(_tables[1], _tables[0] + tableSize0, tableSize1); + generateTables(0, 2, 3, tableSize0); + generateTables(1, 4, 5, tableSize1); + postprocess = true; + } else if (mode < 0) { + _src->copyBytes(d); + postprocess = false; + needrefresh = true; + } else if (mode == 0){ + uint8 *d2 = _tables[0]; + memset(d2, 8, 144); + memset(d2 + 144, 9, 112); + memset(d2 + 256, 7, 24); + memset(d2 + 280, 8, 8); + d2 = _tables[1]; + memset(d2, 5, 32); + tableSize0 = 288; + tableSize1 = 32; + + generateTables(0, 2, 3, tableSize0); + generateTables(1, 4, 5, tableSize1); + postprocess = true; + } else { + error("decompression failure"); + } + + if (!postprocess) + continue; + + int16 cmd = 0; + + do { + cmd = ((int16*) _tables[2])[_src->getKeyLower()]; + _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]); + + if (cmd == 0x11d) { + cmd = 0x200; + } else if (cmd > 0x108) { + cmd = _src->keyMaskedAlign(cmd); + } + + if (!(cmd >> 8)) { + *d++ = cmd & 0xff; + } else if (cmd != 0x100) { + cmd -= 0xfe; + int16 offset = ((int16*) _tables[4])[_src->getKeyLower()]; + _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]); + if ((offset & 0xff) >= 4) { + uint8 newIndex = ((offset & 0xff) >> 1) - 1; + offset = (((offset & 1) + 2) << newIndex); + offset += _src->getKeyMasked(newIndex); + } + + uint8 *s2 = d - 1 - offset; + if (s2 >= dst) { + while (cmd--) + *d++ = *s2++; + } else { + uint32 pos = dst - s2; + s2 += (d - dst); + + if (pos < (uint32) cmd) { + cmd -= pos; + while (pos--) + *d++ = *s2++; + s2 = dst; + } + while (cmd--) + *d++ = *s2++; + } + } + } while (cmd != 0x100); + } + + delete _src; + _src = 0; + + return true; +} + +void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) { + const uint8 *tbl1 = _tables[srcIndex]; + uint8 *tbl2 = _tables[dstIndex]; + const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2]; + + if (!cnt) + return; + + const uint8 *s = tbl1; + memset(_tables16[0], 0, 32); + + for (int i = 0; i < cnt; i++) + _tables16[0][(*s++)]++; + + _tables16[1][1] = 0; + + for (uint16 i = 1, r = 0; i < 16; i++) { + r = (r + _tables16[0][i]) << 1; + _tables16[1][i + 1] = r; + } + + if (_tables16[1][16]) { + uint16 r = 0; + for (uint16 i = 1; i < 16; i++) + r += _tables16[0][i]; + if (r > 1) + error("decompression failure"); + } + + s = tbl1; + uint16 *d = _tables16[2]; + for (int i = 0; i < cnt; i++) { + uint16 t = *s++; + if (t) { + _tables16[1][t]++; + t = _tables16[1][t] - 1; + } + *d++ = t; + } + + s = tbl1; + d = _tables16[2]; + for (int i = 0; i < cnt; i++) { + int8 t = ((int8)(*s++)) - 1; + if (t > 0) { + uint16 v1 = *d; + uint16 v2 = 0; + + do { + v2 = (v2 << 1) | (v1 & 1); + v1 >>= 1; + } while (--t && v1); + + t++; + uint8 c1 = (v1 & 1); + while (t--) { + uint8 c2 = v2 >> 15; + v2 = (v2 << 1) | c1; + c1 = c2; + }; + + *d++ = v2; + } else { + d++; + } + } + + memset(tbl2, 0, 512); + + cnt--; + s = tbl1 + cnt; + d = &_tables16[2][cnt]; + uint16 * bt = (uint16*) tbl3; + uint16 inc = 0; + uint16 cnt2 = 0; + + do { + uint8 t = *s--; + uint16 *s2 = (uint16*) tbl2; + + if (t && t < 9) { + inc = 1 << t; + uint16 o = *d; + + do { + s2[o] = cnt; + o += inc; + } while (!(o & 0xf00)); + + } else if (t > 8) { + if (!bt) + error("decompression failure"); + + t -= 8; + uint8 shiftCnt = 1; + uint8 v = (*d) >> 8; + s2 = &((uint16*) tbl2)[*d & 0xff]; + + do { + if (!*s2) { + *s2 = (uint16)(~cnt2); + *(uint32*)&bt[cnt2] = 0; + cnt2 += 2; + } + + s2 = &bt[(uint16)(~*s2)]; + if (v & shiftCnt) + s2++; + + shiftCnt <<= 1; + } while (--t); + *s2 = cnt; + } + d--; + } while (--cnt >= 0); +} + +uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 ¶) { + const uint16 *t = (const uint16*)tbl; + _src->advSrcBitsByIndex(8); + uint8 newIndex = 0; + uint16 v = _src->getKeyLower(); + + do { + newIndex++; + para = t[((~para) & 0xfffe) | (v & 1)]; + v >>= 1; + } while (para < 0); + + return newIndex; +} + +namespace { + +struct InsArchive { + Common::String filename; + uint32 firstFile; + uint32 startOffset; + uint32 lastFile; + uint32 endOffset; + uint32 totalSize; +}; + +} // end of anonymouse namespace + +Common::Archive *InstallerLoader::load(Resource *owner, const Common::String &filename, const Common::String &extension, const uint8 containerOffset) { + uint32 pos = 0; + uint32 bytesleft = 0; + bool startFile = true; + + Common::String filenameBase =filename; + Common::String filenameTemp; + char filenameExt[4]; + + if (filenameBase.lastChar() != '.') + filenameBase += '.'; + + InsArchive newArchive; + Common::List<InsArchive> archives; + + Common::SeekableReadStream *tmpFile = 0; + + for (int8 currentFile = 1; currentFile; currentFile++) { + sprintf(filenameExt, extension.c_str(), currentFile); + filenameTemp = filenameBase + Common::String(filenameExt); + + if (!(tmpFile = owner->getFileStream(filenameTemp))) { + debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); + break; + } + + tmpFile->seek(pos, SEEK_SET); + uint8 fileId = tmpFile->readByte(); + pos++; + + uint32 size = tmpFile->size() - 1; + if (startFile) { + size -= 4; + if (fileId == currentFile) { + size -= containerOffset; + pos += containerOffset; + tmpFile->seek(containerOffset, SEEK_CUR); + } else { + size = size + 1 - pos; + } + newArchive.filename = filenameBase; + bytesleft = newArchive.totalSize = tmpFile->readUint32LE(); + pos += 4; + newArchive.firstFile = currentFile; + newArchive.startOffset = pos; + startFile = false; + } + + uint32 cs = MIN(size, bytesleft); + bytesleft -= cs; + + delete tmpFile; + tmpFile = 0; + + pos += cs; + if (cs == size) { + if (!bytesleft) { + newArchive.lastFile = currentFile; + newArchive.endOffset = --pos; + archives.push_back(newArchive); + currentFile = -1; + } else { + pos = 0; + } + } else { + startFile = true; + bytesleft = size - cs; + newArchive.lastFile = currentFile--; + newArchive.endOffset = --pos; + archives.push_back(newArchive); + } + } + + FileExpander exp; + CachedArchive::InputEntry newEntry; + uint32 insize = 0; + uint32 outsize = 0; + uint8 *inbuffer = 0; + uint8 *outbuffer = 0; + uint32 inPart1 = 0; + uint32 inPart2 = 0; + uint8 compressionType = 0; + Common::String entryStr; + + CachedArchive::FileInputList fileList; + + pos = 0; + + const uint32 kExecSize = 0x0bba; + const uint32 kHeaderSize = 30; + const uint32 kHeaderSize2 = 46; + + for (Common::List<InsArchive>::iterator a = archives.begin(); a != archives.end(); ++a) { + startFile = true; + for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) { + sprintf(filenameExt, extension.c_str(), i); + filenameTemp = a->filename + Common::String(filenameExt); + + if (!(tmpFile = owner->getFileStream(filenameTemp))) { + debug(3, "couldn't open file '%s'\n", filenameTemp.c_str()); + break; + } + + uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile->size(); + + if (startFile) { + startFile = false; + pos = a->startOffset + kExecSize; + if (pos > size) { + pos -= size; + delete tmpFile; + tmpFile = 0; + continue; + } + } else { + if (inPart2) { + tmpFile->seek(1, SEEK_SET); + tmpFile->read(inbuffer + inPart1, inPart2); + inPart2 = 0; + + if (compressionType > 0) + exp.process(outbuffer, inbuffer, outsize, insize); + else + memcpy(outbuffer, inbuffer, outsize); + + delete[] inbuffer; + inbuffer = 0; + newEntry.data = outbuffer; + newEntry.size = outsize; + newEntry.name = entryStr; + fileList.push_back(newEntry); + } + pos++; + } + + while (pos < size) { + uint8 hdr[43]; + uint32 m = 0; + tmpFile->seek(pos, SEEK_SET); + + if (pos + 42 > size) { + m = size - pos; + uint32 b = 42 - m; + + if (m >= 4) { + uint32 id = tmpFile->readUint32LE(); + if (id == 0x06054B50) { + startFile = true; + break; + } else { + tmpFile->seek(pos, SEEK_SET); + } + } + + sprintf(filenameExt, extension.c_str(), i + 1); + filenameTemp = a->filename + Common::String(filenameExt); + + Common::SeekableReadStream *tmpFile2 = owner->getFileStream(filenameTemp); + tmpFile->read(hdr, m); + tmpFile2->read(hdr + m, b); + delete tmpFile2; + } else { + tmpFile->read(hdr, 42); + } + + uint32 id = READ_LE_UINT32(hdr); + + if (id == 0x04034B50) { + compressionType = hdr[8]; + insize = READ_LE_UINT32(hdr + 18); + outsize = READ_LE_UINT32(hdr + 22); + + uint16 filestrlen = READ_LE_UINT16(hdr + 26); + *(hdr + 30 + filestrlen) = 0; + entryStr = Common::String((const char *)(hdr + 30)); + pos += (kHeaderSize + filestrlen - m); + tmpFile->seek(pos, SEEK_SET); + + outbuffer = new uint8[outsize]; + if (!outbuffer) + error("Out of memory: Can't uncompress installer files"); + + if (!inbuffer) { + inbuffer = new uint8[insize]; + if (!inbuffer) + error("Out of memory: Can't uncompress installer files"); + } + + if ((pos + insize) > size) { + // this is for files that are split between two archive files + inPart1 = size - pos; + inPart2 = insize - inPart1; + tmpFile->read(inbuffer, inPart1); + } else { + tmpFile->read(inbuffer, insize); + inPart2 = 0; + + if (compressionType > 0) + exp.process(outbuffer, inbuffer, outsize, insize); + else + memcpy(outbuffer, inbuffer, outsize); + + delete[] inbuffer; + inbuffer = 0; + newEntry.data = outbuffer; + newEntry.size = outsize; + newEntry.name = entryStr; + fileList.push_back(newEntry); + } + + pos += insize; + if (pos > size) { + pos -= size; + break; + } + } else { + uint32 filestrlen = READ_LE_UINT32(hdr + 28); + pos += (kHeaderSize2 + filestrlen - m); + } + } + delete tmpFile; + tmpFile = 0; + } + } + + archives.clear(); + return new CachedArchive(fileList); +} + +} // end of namespace Kyra diff --git a/engines/kyra/resource_intern.h b/engines/kyra/resource_intern.h new file mode 100644 index 0000000000..1335be5e4e --- /dev/null +++ b/engines/kyra/resource_intern.h @@ -0,0 +1,132 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef KYRA_RESOURCE_INTERN_H +#define KYRA_RESOURCE_INTERN_H + +#include "common/archive.h" +#include "common/hash-str.h" +#include "common/hashmap.h" +#include "common/str.h" +#include "common/list.h" + +namespace Kyra { + +class Resource; + +class PlainArchive : public Common::Archive { +public: + struct InputEntry { + Common::String name; + + uint32 offset; + uint32 size; + }; + + typedef Common::List<InputEntry> FileInputList; + + PlainArchive(Resource *owner, const Common::String &filename, const FileInputList &files); + + bool hasFile(const Common::String &name); + int getAllNames(Common::StringList &list); + Common::SeekableReadStream *openFile(const Common::String &name); +private: + struct Entry { + uint32 offset; + uint32 size; + }; + + typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; + + Resource *_owner; + Common::String _filename; + FileMap _files; +}; + +class CachedArchive : public Common::Archive { +public: + struct InputEntry { + Common::String name; + + byte *data; + uint32 size; + }; + + typedef Common::List<InputEntry> FileInputList; + + CachedArchive(const FileInputList &files); + ~CachedArchive(); + + bool hasFile(const Common::String &name); + int getAllNames(Common::StringList &list); + Common::SeekableReadStream *openFile(const Common::String &name); +private: + struct Entry { + byte *data; + uint32 size; + }; + + typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; + FileMap _files; +}; + + +class ResArchiveLoader { +public: + virtual ~ResArchiveLoader() {} + virtual bool checkFilename(Common::String filename) const = 0; + virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0; + virtual Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const = 0; +}; + +class ResLoaderPak : public ResArchiveLoader { +public: + bool checkFilename(Common::String filename) const; + bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; + Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; +}; + +class ResLoaderInsMalcolm : public ResArchiveLoader { +public: + bool checkFilename(Common::String filename) const; + bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; + Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; +}; + +class ResLoaderTlk : public ResArchiveLoader { +public: + bool checkFilename(Common::String filename) const; + bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const; + Common::Archive *load(Resource *owner, const Common::String &filename, Common::SeekableReadStream &stream) const; +}; + +class InstallerLoader { +public: + static Common::Archive *load(Resource *owner, const Common::String &filename, const Common::String &extension, const uint8 offset); +}; + +} // end of namespace Kyra + +#endif diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 31c5e15fa6..76089fdb2c 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -26,10 +26,11 @@ #include "common/endian.h" #include "common/savefile.h" #include "common/system.h" +#include "graphics/thumbnail.h" #include "kyra/kyra_v1.h" -#define CURRENT_SAVE_VERSION 13 +#define CURRENT_SAVE_VERSION 14 #define GF_FLOPPY (1 << 0) #define GF_TALKIE (1 << 1) @@ -37,11 +38,12 @@ namespace Kyra { -KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) { +KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) { uint32 type = in->readUint32BE(); header.originalSave = false; header.oldHeader = false; header.flags = 0; + header.thumbnail = 0; if (type == MKID_BE('KYRA') || type == MKID_BE('ARYK')) { // old Kyra1 header ID header.gameID = GI_KYRA1; @@ -108,6 +110,19 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab if (header.version >= 2) header.flags = in->readUint32BE(); + if (header.version >= 14) { + if (loadThumbnail) { + header.thumbnail = new Graphics::Surface(); + assert(header.thumbnail); + if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { + delete header.thumbnail; + header.thumbnail = 0; + } + } else { + Graphics::skipThumbnailHeader(*in); + } + } + return (in->ioFailed() ? kRSHEIoError : kRSHENoError); } @@ -118,7 +133,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena if (!(in = _saveFileMan->openForLoading(filename))) return 0; - kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header); + kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header); if (errorCode != kRSHENoError) { if (errorCode == kRSHEInvalidType) warning("No ScummVM Kyra engine savefile header."); @@ -162,9 +177,9 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena return in; } -Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const { - debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName); - if (_quitFlag) +Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const { + debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s', %p)", filename, saveName, (const void *)thumbnail); + if (quit()) return 0; Common::WriteStream *out = 0; @@ -191,20 +206,27 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con return 0; } + if (thumbnail) + Graphics::saveThumbnail(*out, *thumbnail); + else + Graphics::saveThumbnail(*out); + return out; } const char *KyraEngine_v1::getSavegameFilename(int num) { static Common::String filename; + filename = getSavegameFilename(_targetName, num); + return filename.c_str(); +} +Common::String KyraEngine_v1::getSavegameFilename(const Common::String &target, int num) { assert(num >= 0 && num <= 999); char extension[5]; - sprintf(extension, "%.3d", num); + sprintf(extension, "%03d", num); - filename = _targetName + "." + extension; - - return filename.c_str(); + return target + "." + extension; } bool KyraEngine_v1::saveFileLoadable(int slot) { @@ -222,5 +244,12 @@ bool KyraEngine_v1::saveFileLoadable(int slot) { return false; } +void KyraEngine_v1::checkAutosave() { + if (shouldPerformAutoSave(_lastAutosave)) { + saveGame(getSavegameFilename(999), "Autosave", 0); + _lastAutosave = _system->getMillis(); + } +} + } // end of namespace Kyra diff --git a/engines/kyra/saveload_hof.cpp b/engines/kyra/saveload_hof.cpp index 954cbccfa9..be7a74e1c3 100644 --- a/engines/kyra/saveload_hof.cpp +++ b/engines/kyra/saveload_hof.cpp @@ -35,10 +35,10 @@ namespace Kyra { -void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_HoF::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) { warning("Can't open file '%s', game not loadable", fileName); return; @@ -118,7 +118,7 @@ void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) { out->finalize(); // check for errors - if (out->ioFailed()) + if (out->err()) warning("Can't write file '%s'. (Disk full?)", fileName); else debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); @@ -279,7 +279,7 @@ void KyraEngine_HoF::loadGame(const char *fileName) { _sceneExit3 = in.readUint16(); _sceneExit4 = in.readUint16(); - if (saveFile->ioFailed()) + if (saveFile->err() || saveFile->eos()) error("Load failed ('%s', '%s').", fileName, header.description.c_str()); else debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str()); diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp index 8af73acc61..f0d9f1ba82 100644 --- a/engines/kyra/saveload_lok.cpp +++ b/engines/kyra/saveload_lok.cpp @@ -206,7 +206,7 @@ void KyraEngine_LoK::loadGame(const char *fileName) { _mousePressFlag = false; setMousePos(brandonX, brandonY); - if (in->ioFailed()) + if (in->err() || in->eos()) error("Load failed ('%s', '%s').", fileName, header.description.c_str()); else debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str()); @@ -218,13 +218,13 @@ void KyraEngine_LoK::loadGame(const char *fileName) { delete in; } -void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); - if (_quitFlag) + if (quit()) return; - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) return; @@ -289,7 +289,7 @@ void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) { out->finalize(); // check for errors - if (out->ioFailed()) + if (out->err()) warning("Can't write file '%s'. (Disk full?)", fileName); else debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); diff --git a/engines/kyra/saveload_mr.cpp b/engines/kyra/saveload_mr.cpp index 51efc33723..0db82863ab 100644 --- a/engines/kyra/saveload_mr.cpp +++ b/engines/kyra/saveload_mr.cpp @@ -32,10 +32,10 @@ namespace Kyra { -void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "KyraEngine_MR::saveGame('%s', '%s')", fileName, saveName); +void KyraEngine_MR::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) { + debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb); - Common::OutSaveFile *out = openSaveForWriting(fileName, saveName); + Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) { warning("Can't open file '%s', game not loadable", fileName); return; @@ -112,7 +112,7 @@ void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) { out->finalize(); // check for errors - if (out->ioFailed()) + if (out->err()) warning("Can't write file '%s'. (Disk full?)", fileName); else debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); @@ -283,7 +283,7 @@ void KyraEngine_MR::loadGame(const char *fileName) { _sceneExit3 = in.readUint16(); _sceneExit4 = in.readUint16(); - if (saveFile->ioFailed()) + if (saveFile->err() || saveFile->eos()) error("Load failed ('%s', '%s').", fileName, header.description.c_str()); else debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str()); diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp index 62df683ea2..df9fccaab9 100644 --- a/engines/kyra/scene_hof.cpp +++ b/engines/kyra/scene_hof.cpp @@ -277,7 +277,7 @@ int KyraEngine_HoF::trySceneChange(int *moveTable, int unk1, int updateChar) { int changedScene = 0; const int *moveTableStart = moveTable; _unk4 = 0; - while (running && !_quitFlag) { + while (running && !quit()) { if (*moveTable >= 0 && *moveTable <= 7) { _mainCharacter.facing = getOppositeFacingDirection(*moveTable); unkFlag = true; @@ -517,7 +517,7 @@ void KyraEngine_HoF::runSceneScript7() { void KyraEngine_HoF::initSceneAnims(int unk1) { debugC(9, kDebugLevelMain, "KyraEngine_HoF::initSceneAnims(%d)", unk1); - for (int i = 0; i < ARRAYSIZE(_animObjects); ++i) + for (int i = 0; i < 41; ++i) _animObjects[i].enabled = 0; bool animInit = false; diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp index 53c0cb5380..ad4ce63b6c 100644 --- a/engines/kyra/scene_mr.cpp +++ b/engines/kyra/scene_mr.cpp @@ -654,7 +654,7 @@ int KyraEngine_MR::trySceneChange(int *moveTable, int unk1, int updateChar) { const int *moveTableStart = moveTable; _unk4 = 0; - while (running && !_quitFlag) { + while (running && !quit()) { if (*moveTable >= 0 && *moveTable <= 7) { _mainCharacter.facing = getOppositeFacingDirection(*moveTable); unkFlag = true; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 0cde066cc0..4bcde9a679 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -188,19 +188,19 @@ void Screen::setResolution() { if (_vm->gameFlags().useHiResOverlay) { _system->beginGFXTransaction(); - _vm->initCommonGFX(true); if (_debugEnabled) _system->initSize(960, 400); else _system->initSize(640, 400); + _vm->initCommonGFX(true); _system->endGFXTransaction(); } else { _system->beginGFXTransaction(); - _vm->initCommonGFX(false); if (_debugEnabled) _system->initSize(640, 200); else _system->initSize(320, 200); + _vm->initCommonGFX(false); _system->endGFXTransaction(); } @@ -476,6 +476,25 @@ void Screen::setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue) { setScreenPalette(_currentPalette); } +void Screen::getRealPalette(int num, uint8 *dst) { + debugC(9, kDebugLevelScreen, "Screen::getRealPalette(%d, %p)", num, (const void *)dst); + const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); + const uint8 *palData = getPalette(num); + + if (!palData) { + memset(dst, 0, colors * 3); + return; + } + + for (int i = 0; i < colors; ++i) { + dst[0] = (palData[0] << 2) | (palData[0] & 3); + dst[1] = (palData[1] << 2) | (palData[1] & 3); + dst[2] = (palData[2] << 2) | (palData[2] & 3); + dst += 3; + palData += 3; + } +} + void Screen::setScreenPalette(const uint8 *palData) { debugC(9, kDebugLevelScreen, "Screen::setScreenPalette(%p)", (const void *)palData); @@ -554,19 +573,16 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag copyOverlayRegion(x1, y1, x2, y2, w, h, srcPage, dstPage); - if (flags & CR_X_FLIPPED) { + if (flags & CR_NO_P_CHECK) { while (h--) { - for (int i = 0; i < w; ++i) { - if (src[i] || (flags & CR_NO_P_CHECK)) - dst[w-i] = src[i]; - } + memcpy(dst, src, w); src += SCREEN_W; dst += SCREEN_W; } } else { while (h--) { for (int i = 0; i < w; ++i) { - if (src[i] || (flags & CR_NO_P_CHECK)) + if (src[i]) dst[i] = src[i]; } src += SCREEN_W; @@ -2739,21 +2755,7 @@ bool Screen::loadPalette(const char *filename, uint8 *palData) { if (palData && fileSize) { debugC(9, kDebugLevelScreen,"Loading a palette of size %u from '%s'", fileSize, filename); - if (_vm->gameFlags().platform == Common::kPlatformAmiga) { - assert(fileSize % 2 == 0); - assert(fileSize / 2 <= 256); - fileSize >>= 1; - const uint16 *src = (const uint16 *)srcData; - for (uint i = 0; i < fileSize; ++i) { - uint16 col = READ_BE_UINT16(src); ++src; - palData[2] = (col & 0xF) << 2; col >>= 4; - palData[1] = (col & 0xF) << 2; col >>= 4; - palData[0] = (col & 0xF) << 2; col >>= 4; - palData += 3; - } - } else { - memcpy(palData, srcData, fileSize); - } + loadPalette(srcData, palData, fileSize); } delete[] srcData; return true; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 99ba2d7c5f..58744a9d2a 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -74,8 +74,7 @@ public: }; enum CopyRegionFlags { - CR_X_FLIPPED = 0x01, - CR_NO_P_CHECK = 0x02 + CR_NO_P_CHECK = 0x01 }; enum DrawShapeFlags { @@ -153,6 +152,8 @@ public: void setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue); void setScreenPalette(const uint8 *palData); const uint8 *getScreenPalette() const { return _screenPalette; } + + void getRealPalette(int num, uint8 *dst); uint8 *getPalette(int num); // gui specific (processing on _curPage) diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp index 011c90dde9..da88abc61f 100644 --- a/engines/kyra/screen_lok.cpp +++ b/engines/kyra/screen_lok.cpp @@ -147,8 +147,14 @@ void Screen_LoK::savePageToDisk(const char *file, int page) { void Screen_LoK::loadPageFromDisk(const char *file, int page) { debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page); + if (!_saveLoadPage[page/2]) { + warning("trying to restore page %d, but no backup found", page); + return; + } + copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]); delete[] _saveLoadPage[page/2]; + _saveLoadPage[page/2] = 0; if (_saveLoadPageOvl[page/2]) { uint8 *dstPage = getOverlayPtr(page); @@ -160,7 +166,17 @@ void Screen_LoK::loadPageFromDisk(const char *file, int page) { memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE); delete[] _saveLoadPageOvl[page/2]; _saveLoadPageOvl[page/2] = 0; - } _saveLoadPage[page/2] = 0; + } +} + +void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) { + debugC(9, kDebugLevelScreen, "Screen_LoK::queryPageFromDisk('%s', %d, %p)", file, page, (const void *)buffer); + if (!_saveLoadPage[page/2]) { + warning("trying to query page %d, but no backup found", page); + return; + } + + memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H); } void Screen_LoK::deletePageFromDisk(int page) { diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h index 74df23a543..5b4b8a9266 100644 --- a/engines/kyra/screen_lok.h +++ b/engines/kyra/screen_lok.h @@ -50,6 +50,7 @@ public: void savePageToDisk(const char *file, int page); void loadPageFromDisk(const char *file, int page); + void queryPageFromDisk(const char *file, int page, uint8 *buffer); void deletePageFromDisk(int page); void copyBackgroundBlock(int x, int page, int flag); diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index b10a4b32bf..dba09f08ef 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -255,13 +255,13 @@ uint32 ScriptFileParser::getIFFBlockSize(const uint32 chunkName) { _stream->seek(_startOffset + 0x0C); - while (_stream->pos() < _endOffset) { + while ((uint)_stream->pos() < _endOffset) { uint32 chunk = _stream->readUint32LE(); uint32 size_temp = _stream->readUint32BE(); if (chunk != chunkName) { _stream->seek((size_temp + 1) & (~1), SEEK_CUR); - assert(_stream->pos() <= _endOffset); + assert((uint)_stream->pos() <= _endOffset); } else { size = size_temp; break; @@ -274,13 +274,13 @@ uint32 ScriptFileParser::getIFFBlockSize(const uint32 chunkName) { bool ScriptFileParser::loadIFFBlock(const uint32 chunkName, void *loadTo, uint32 ptrSize) { _stream->seek(_startOffset + 0x0C); - while (_stream->pos() < _endOffset) { + while ((uint)_stream->pos() < _endOffset) { uint32 chunk = _stream->readUint32LE(); uint32 chunkSize = _stream->readUint32BE(); if (chunk != chunkName) { _stream->seek((chunkSize + 1) & (~1), SEEK_CUR); - assert(_stream->pos() <= _endOffset); + assert((uint)_stream->pos() <= _endOffset); } else { uint32 loadSize = 0; @@ -435,59 +435,35 @@ void EMCInterpreter::cmd_eval(EMCState* script) { switch (_parameter) { case 0: - if (!val2 || !val1) - ret = 0; - else - ret = 1; + ret = (val2 && val1) ? 1 : 0; break; case 1: - if (val2 || val1) - ret = 1; - else - ret = 0; + ret = (val2 || val1) ? 1 : 0; break; case 2: - if (val1 == val2) - ret = 1; - else - ret = 0; + ret = (val1 == val2) ? 1 : 0; break; case 3: - if (val1 != val2) - ret = 1; - else - ret = 0; + ret = (val1 != val2) ? 1 : 0; break; case 4: - if (val1 > val2) - ret = 1; - else - ret = 0; + ret = (val1 > val2) ? 1 : 0; break; case 5: - if (val1 >= val2) - ret = 1; - else - ret = 0; + ret = (val1 >= val2) ? 1 : 0; break; case 6: - if (val1 < val2) - ret = 1; - else - ret = 0; + ret = (val1 < val2) ? 1 : 0; break; case 7: - if (val1 <= val2) - ret = 1; - else - ret = 0; + ret = (val1 <= val2) ? 1 : 0; break; case 8: diff --git a/engines/kyra/script.h b/engines/kyra/script.h index 2b97a83289..6e08017974 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -47,7 +47,7 @@ struct EMCData { }; struct EMCState { - uint16 *ip; + const uint16 *ip; const EMCData *dataPtr; int16 retValue; uint16 bp; diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp index efa0f8e48f..e965a075bd 100644 --- a/engines/kyra/script_lok.cpp +++ b/engines/kyra/script_lok.cpp @@ -1747,7 +1747,8 @@ int KyraEngine_LoK::o1_pauseMusicSeconds(EMCState *script) { } int KyraEngine_LoK::o1_resetMaskRegion(EMCState *script) { - warning("STUB: o1_resetMaskRegion"); + debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_resetMaskRegion(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + _screen->fillRect(stackPos(1), stackPos(2), stackPos(1)+stackPos(3), stackPos(2)+stackPos(4), 0, 5); return 0; } diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 9a059ead2a..bc71e72ce4 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -293,7 +293,7 @@ int KyraEngine_MR::o3_updateScore(EMCState *script) { int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script); - saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); + saveGame(getSavegameFilename(999), "Autosave", 0); return 0; } @@ -786,7 +786,7 @@ int KyraEngine_MR::o3_daggerWarning(EMCState *script) { _screen->_curPage = curPageBackUp; _screen->showMouse(); - while (!_quitFlag) { + while (!quit()) { int keys = checkInput(0); removeInputTop(); diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index 635db3629c..7915a33996 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -75,7 +75,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _seqEndTime = 0; _menuChoice = 0; - for (int seqNum = startSeq; seqNum <= endSeq && !((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice); seqNum++) { + for (int seqNum = startSeq; seqNum <= endSeq && !((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice); seqNum++) { _screen->clearPage(0); _screen->clearPage(8); memcpy(_screen->getPalette(1), _screen->getPalette(0), 0x300); @@ -131,7 +131,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { seq_sequenceCommand(cseq.startupCommand); - if (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + if (!((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _screen->copyPage(2, 0); _screen->updateScreen(); } @@ -165,7 +165,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _seqWsaCurrentFrame = cseq.startFrame; bool loop = true; - while (loop && !((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + while (loop && !((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; if (_seqWsa || !cb) @@ -189,16 +189,16 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { seq_processWSAs(); seq_processText(); - if ((_seqWsa || !cb) && !((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + if ((_seqWsa || !cb) && !((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _screen->copyPage(2, 0); _screen->updateScreen(); } bool loop2 = true; - while (loop2 && !((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + while (loop2 && !((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { if (_seqWsa) { seq_processText(); - if (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + if (!((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _screen->copyPage(2, 0); _screen->updateScreen(); } @@ -230,7 +230,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { } else { _seqFrameDelay = cseq.frameDelay; _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; - while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + while (!((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _seqSubFrameStartTime = _system->getMillis(); seq_processWSAs(); if (cb) @@ -262,7 +262,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { dl = ct; _seqEndTime = _system->getMillis() + dl; - while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) { + while (!((skipFlag() && allowSkip) || quit() || (_abortIntroFlag && allowSkip) || _menuChoice)) { _seqSubFrameStartTime = _system->getMillis(); seq_processWSAs(); @@ -2267,7 +2267,7 @@ void KyraEngine_HoF::seq_loadNestedSequence(int wsaNum, int seqNum) { void KyraEngine_HoF::seq_nestedSequenceFrame(int command, int wsaNum) { int xa = 0, ya = 0; command--; - if (!_activeWSA[wsaNum].movie || skipFlag() || _quitFlag || _abortIntroFlag) + if (!_activeWSA[wsaNum].movie || skipFlag() || quit() || _abortIntroFlag) return; switch (command) { @@ -2467,7 +2467,7 @@ bool KyraEngine_HoF::seq_processNextSubFrame(int wsaNum) { void KyraEngine_HoF::seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor) { uint8 colormap[16]; - if (skipFlag() || _quitFlag || _abortIntroFlag || _menuChoice) + if (skipFlag() || quit() || _abortIntroFlag || _menuChoice) return; memset(&_screen->getPalette(0)[0x2fa], 0x3f, 6); @@ -2830,6 +2830,9 @@ void KyraEngine_HoF::seq_init() { _res->unloadAllPakFiles(); _res->loadPakFile(StaticResource::staticDataFilename()); _res->loadFileList(_sequencePakList, _sequencePakListSize); + + if (_flags.platform == Common::kPlatformPC98) + _sound->loadSoundFile("sound.dat"); int numShp = -1; @@ -2954,7 +2957,7 @@ void KyraEngine_HoF::seq_makeBookAppear() { ++_invWsa.curFrame; - if (_invWsa.curFrame >= _invWsa.lastFrame && !_quitFlag) + if (_invWsa.curFrame >= _invWsa.lastFrame && !quit()) break; switch (_invWsa.curFrame) { diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index 3a497a258f..77cfbed2d0 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -34,7 +34,6 @@ #include "kyra/text.h" #include "kyra/timer.h" -#include "common/events.h" #include "common/system.h" #include "common/savefile.h" @@ -164,7 +163,7 @@ void KyraEngine_LoK::seq_introLogos() { _screen->updateScreen(); _screen->fadeFromBlack(); - if (_seq->playSequence(_seq_WestwoodLogo, _skipFlag) || _quitFlag) { + if (_seq->playSequence(_seq_WestwoodLogo, _skipFlag) || quit()) { _screen->fadeToBlack(); _screen->clearPage(0); return; @@ -176,14 +175,14 @@ void KyraEngine_LoK::seq_introLogos() { _screen->setScreenPalette(_screen->_currentPalette); } - if ((_seq->playSequence(_seq_KyrandiaLogo, _skipFlag) && !seq_skipSequence()) || _quitFlag) { + if ((_seq->playSequence(_seq_KyrandiaLogo, _skipFlag) && !seq_skipSequence()) || quit()) { _screen->fadeToBlack(); _screen->clearPage(0); return; } _screen->fillRect(0, 179, 319, 199, 0); - if (_quitFlag) + if (quit()) return; if (_flags.platform == Common::kPlatformAmiga) { @@ -223,10 +222,10 @@ void KyraEngine_LoK::seq_introLogos() { oldDistance = distance; delay(10); - } while (!doneFlag && !_quitFlag && !_abortIntroFlag); + } while (!doneFlag && !quit() && !_abortIntroFlag); } - if (_quitFlag) + if (quit()) return; _seq->playSequence(_seq_Forest, true); @@ -1030,7 +1029,7 @@ void KyraEngine_LoK::seq_brandonToStone() { void KyraEngine_LoK::seq_playEnding() { debugC(9, kDebugLevelMain, "KyraEngine_LoK::seq_playEnding()"); - if (_quitFlag) + if (quit()) return; _screen->hideMouse(); _screen->_curPage = 0; @@ -1186,8 +1185,8 @@ void KyraEngine_LoK::seq_playCredits() { case Common::EVENT_KEYDOWN: finished = true; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - quitGame(); finished = true; break; default: @@ -1211,7 +1210,7 @@ void KyraEngine_LoK::seq_playCredits() { bool KyraEngine_LoK::seq_skipSequence() const { debugC(9, kDebugLevelMain, "KyraEngine_LoK::seq_skipSequence()"); - return _quitFlag || _abortIntroFlag; + return quit() || _abortIntroFlag; } int KyraEngine_LoK::handleMalcolmFlag() { diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index e5294eb15d..2f7ac27ac5 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -429,7 +429,7 @@ public: MidiChannel *allocateChannel() { return 0; } MidiChannel *getPercussionChannel() { return 0; } - static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, + static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel); private: @@ -492,7 +492,7 @@ public: void process(); void loadSoundFile(uint file) {} - void loadSoundFile(Common::String) {} + void loadSoundFile(Common::String file); void playTrack(uint8 track); void haltTrack(); @@ -507,6 +507,7 @@ protected: bool _useFmSfx; uint8 *_musicTrackData; + uint8 *_sfxTrackData; TownsPC98_OpnDriver *_driver; }; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index ec1962a58f..5bb09e5dc9 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -23,7 +23,6 @@ * */ - #include "common/system.h" #include "kyra/resource.h" #include "kyra/sound.h" @@ -64,13 +63,13 @@ public: MidiDriver *device() { return 0; } byte getNumber() { return 0; } void release() { } - void send(uint32 b) { } + void send(uint32) { } void noteOff(byte note); void noteOn(byte note, byte onVelo); - void programChange(byte program) {} + void programChange(byte) {} void pitchBend(int16 value); void controlChange(byte control, byte value); - void pitchBendFactor(byte value) { } + void pitchBendFactor(byte) { } void sysEx_customInstrument(uint32 unused, const byte *instr); protected: @@ -427,7 +426,7 @@ void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) { return; } - float phaseStep = SoundTowns::semitoneAndSampleRate_to_sampleStep(_note, _voice->_snd[_current]->keyNote - + float phaseStep = SoundTowns::calculatePhaseStep(_note, _voice->_snd[_current]->keyNote - _voice->_env[_current]->rootKeyOffset, _voice->_snd[_current]->samplingRate, _rate, _frequencyOffs); int32 looplength = _voice->_snd[_current]->loopLength; @@ -819,7 +818,8 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { } } - while (true) { + bool loop = true; + while (loop) { byte cmd = *pos; byte evt = (cmd & 0xF0); @@ -853,7 +853,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.basic.param2 = onVelo; pos += 12; - break; + loop = false; } else { pos += 6; } @@ -870,7 +870,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.basic.param1 = pos[4]; info.basic.param2 = pos[5]; pos += 6; - break; + loop = false; } else { pos += 6; } @@ -889,7 +889,7 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { _tempo[2] = tempo & 0xff; info.ext.data = (byte*) _tempo; pos += 6; - break; + loop = false; } else if (cmd == 0xFD || cmd == 0xFE) { // End of track. if (_autoLoop) { @@ -906,12 +906,12 @@ void Towns_EuphonyParser::parseNextEvent(EventInfo &info) { info.event = 0xFF; info.ext.type = 0x2F; info.ext.data = pos; - break; + loop = false; } else { error("Unknown Euphony music event 0x%02X", (int)cmd); memset(&info, 0, sizeof(info)); pos = 0; - break; + loop = false; } } _position._play_pos = pos; @@ -1085,7 +1085,7 @@ void Towns_EuphonyTrackQueue::initDriver() { class TownsPC98_OpnOperator { public: - TownsPC98_OpnOperator(double rate, const uint8 *rateTable, + TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); ~TownsPC98_OpnOperator() {} @@ -1095,7 +1095,7 @@ public: void frequency(int freq); void updatePhaseIncrement(); void recalculateRates(); - void generateOutput(int phasebuf, int *_feedbuf, int &out); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } void detune(int value) { _detn = &_detnTbl[value << 5]; } @@ -1111,6 +1111,7 @@ public: protected: EnvelopeState _state; + bool _playing; uint32 _feedbackLevel; uint32 _multiple; uint32 _totalLevel; @@ -1137,8 +1138,8 @@ protected: const int32 *_tLvlTbl; const int32 *_detnTbl; - const double _tickLength; - double _tick; + const uint32 _tickLength; + uint32 _timer; int32 _currentLevel; struct EvpState { @@ -1147,23 +1148,31 @@ protected: } fs_a, fs_d, fs_s, fs_r; }; -TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable, +TownsPC98_OpnOperator::TownsPC98_OpnOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), - _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0), + _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2), _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), _phase(0), _state(s_ready) { - + reset(); } void TownsPC98_OpnOperator::keyOn() { + if (_playing) + return; + + _playing = true; _state = s_attacking; _phase = 0; } void TownsPC98_OpnOperator::keyOff() { + if (!_playing) + return; + + _playing = false; if (_state != s_ready) _state = s_releasing; } @@ -1172,6 +1181,7 @@ void TownsPC98_OpnOperator::frequency(int freq) { uint8 block = (freq >> 11); uint16 pos = (freq & 0x7ff); uint8 c = pos >> 7; + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); _frequency = _fTbl[pos << 1] >> (7 - block); } @@ -1204,44 +1214,44 @@ void TownsPC98_OpnOperator::recalculateRates() { fs_r.shift = _rshiftTbl[r + k]; } -void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) { +void TownsPC98_OpnOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) { if (_state == s_ready) return; - _tick += _tickLength; - while (_tick > 0x30000) { - _tick -= 0x30000; + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; ++_tickCount; int32 levelIncrement = 0; uint32 targetTime = 0; int32 targetLevel = 0; - EnvelopeState next_state = s_ready; + EnvelopeState nextState = s_ready; switch (_state) { case s_ready: return; case s_attacking: - next_state = s_decaying; + nextState = s_decaying; targetTime = (1 << fs_a.shift) - 1; targetLevel = 0; levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; break; case s_decaying: targetTime = (1 << fs_d.shift) - 1; - next_state = s_sustaining; + nextState = s_sustaining; targetLevel = _sustainLevel; levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; break; case s_sustaining: targetTime = (1 << fs_s.shift) - 1; - next_state = s_ready; + nextState = s_sustaining; targetLevel = 1023; levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; break; case s_releasing: targetTime = (1 << fs_r.shift) - 1; - next_state = s_ready; + nextState = s_ready; targetLevel = 1023; levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; break; @@ -1249,31 +1259,29 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out if (!(_tickCount & targetTime)) { _currentLevel += levelIncrement; - if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) { + if ((_state == s_attacking && _currentLevel <= targetLevel) || (_state != s_attacking && _currentLevel >= targetLevel)) { if (_state != s_decaying) _currentLevel = targetLevel; - if (_state != s_sustaining) - _state = next_state; + _state = nextState; } } } uint32 lvlout = _totalLevel + (uint32) _currentLevel; - int outp = 0; - int *i = &outp, *o = &outp; + + int32 outp = 0; + int32 *i = &outp, *o = &outp; int phaseShift = 0; - if (_feedbuf) { - o = &_feedbuf[0]; - i = &_feedbuf[1]; - phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0; - if (phasebuf == -1) - *i = 0; + if (feed) { + o = &feed[0]; + i = &feed[1]; + phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0; *o = *i; } else { phaseShift = phasebuf << 15; - } + } if (lvlout < 832) { uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) @@ -1285,15 +1293,11 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out _phase += _phaseIncrement; out += *o; - if (out > 32767) - out = 32767; - if (out < -32767) - out = -32767; } void TownsPC98_OpnOperator::reset(){ keyOff(); - _tick = 0; + _timer = 0; _keyScale2 = 0; _currentLevel = 1023; @@ -1306,7 +1310,7 @@ void TownsPC98_OpnOperator::reset(){ decayRate(0); releaseRate(0); sustainRate(0); - feedbackLevel(0); + feedbackLevel(0); totalLevel(127); } @@ -1332,40 +1336,34 @@ public: virtual ~TownsPC98_OpnChannel(); virtual void init(); - typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); - typedef enum channelState { CHS_RECALCFREQ = 0x01, CHS_KEYOFF = 0x02, - CHS_SSG = 0x04, - CHS_PITCHWHEELOFF = 0x08, - CHS_ALL_BUT_EOT = 0x0f, + CHS_SSGOFF = 0x04, + CHS_VBROFF = 0x08, + CHS_ALLOFF = 0x0f, + CHS_PROTECT = 0x40, CHS_EOT = 0x80 } ChannelState; virtual void loadData(uint8 *data); virtual void processEvents(); virtual void processFrequency(); - bool processControlEvent(uint8 cmd); - void writeReg(uint8 regAdress, uint8 value); + virtual bool processControlEvent(uint8 cmd); virtual void keyOn(); - virtual void keyOff(); - + void keyOff(); + void setOutputLevel(); - void fadeStep(); + virtual void fadeStep(); void reset(); - void updateEnv(); - void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed); - - bool _enableLeft; - bool _enableRight; - bool _updateEnvelopes; - const uint8 _idFlag; - int _feedbuf[3]; + const uint8 _idFlag; protected: + void setupVibrato(); + bool processVibrato(); + bool control_dummy(uint8 para); bool control_f0_setPatch(uint8 para); bool control_f1_presetOutputLevel(uint8 para); @@ -1374,52 +1372,47 @@ protected: bool control_f4_setOutputLevel(uint8 para); bool control_f5_setTempo(uint8 para); bool control_f6_repeatSection(uint8 para); - bool control_f7_setupPitchWheel(uint8 para); - bool control_f8_togglePitchWheel(uint8 para); + bool control_f7_setupVibrato(uint8 para); + bool control_f8_toggleVibrato(uint8 para); bool control_fa_writeReg(uint8 para); - bool control_fb_incOutLevel(uint8 para); - bool control_fc_decOutLevel(uint8 para); + virtual bool control_fb_incOutLevel(uint8 para); + virtual bool control_fc_decOutLevel(uint8 para); bool control_fd_jump(uint8 para); - bool control_ff_endOfTrack(uint8 para); - - bool control_f0_setPatchSSG(uint8 para); - bool control_f1_setTotalLevel(uint8 para); - bool control_f4_setAlgorithm(uint8 para); - bool control_f9_unkSSG(uint8 para); - bool control_fb_incOutLevelSSG(uint8 para); - bool control_fc_decOutLevelSSG(uint8 para); - bool control_ff_endOfTrackSSG(uint8 para); + virtual bool control_ff_endOfTrack(uint8 para); uint8 _ticksLeft; uint8 _algorithm; - uint8 _instrID; + uint8 _instr; uint8 _totalLevel; uint8 _frqBlockMSB; int8 _frqLSB; uint8 _keyOffTime; - bool _protect; + bool _hold; uint8 *_dataPtr; - uint8 _ptchWhlInitDelayLo; - uint8 _ptchWhlInitDelayHi; - int16 _ptchWhlModInitVal; - uint8 _ptchWhlDuration; - uint8 _ptchWhlCurDelay; - int16 _ptchWhlModCurVal; - uint8 _ptchWhlDurLeft; - uint16 frequency; + uint8 _vbrInitDelayHi; + uint8 _vbrInitDelayLo; + int16 _vbrModInitVal; + uint8 _vbrDuration; + uint8 _vbrCurDelay; + int16 _vbrModCurVal; + uint8 _vbrDurLeft; + uint16 _frequency; + uint8 _block; uint8 _regOffset; uint8 _flags; - uint8 _ssg1; - uint8 _ssg2; + uint8 _ssgTl; + uint8 _ssgStep; + uint8 _ssgTicksLeft; + uint8 _ssgTargetLvl; + uint8 _ssgStartLvl; const uint8 _chanNum; const uint8 _keyNum; const uint8 _part; TownsPC98_OpnDriver *_drv; - TownsPC98_OpnOperator **_opr; - uint16 _frqTemp; + typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para); const ControlEventFunc *controlEvents; }; @@ -1427,24 +1420,169 @@ class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel { public: TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); - ~TownsPC98_OpnChannelSSG() {} + virtual ~TownsPC98_OpnChannelSSG() {} void init(); + virtual void loadData(uint8 *data); void processEvents(); void processFrequency(); + bool processControlEvent(uint8 cmd); void keyOn(); - void keyOff(); + void nextShape(); + + void protect(); + void restore(); + + void fadeStep(); + +protected: + void setOutputLevel(uint8 lvl); + + bool control_f0_setInstr(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_loadCustomPatch(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_OpnChannelSSG::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +class TownsPC98_OpnSfxChannel : public TownsPC98_OpnChannelSSG { +public: + TownsPC98_OpnSfxChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} + ~TownsPC98_OpnSfxChannel() {} + + void loadData(uint8 *data); +}; + +class TownsPC98_OpnChannelPCM : public TownsPC98_OpnChannel { +public: + TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + ~TownsPC98_OpnChannelPCM() {} + void init(); + void loadData(uint8 *data); + void processEvents(); + bool processControlEvent(uint8 cmd); private: - void opn_SSG_UNK(uint8 a); + bool control_f1_prcStart(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_OpnChannelPCM::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; }; +class TownsPC98_OpnSquareSineSource { +public: + TownsPC98_OpnSquareSineSource(const uint32 timerbase); + ~TownsPC98_OpnSquareSineSource(); -class TownsPC98_OpnDriver : public Audio::AudioStream { -friend class TownsPC98_OpnChannel; -friend class TownsPC98_OpnChannelSSG; + void init(const int *rsTable, const int *rseTable); + void reset(); + void writeReg(uint8 address, uint8 value, bool force = false); + + void nextTick(int32 *buffer, uint32 bufferSize); + + uint8 chanEnable() { return _chanEnable; } +private: + void updatesRegs(); + + uint8 _updateRequestBuf[32]; + int _updateRequest; + int _rand; + + int8 _evpTimer; + uint32 _pReslt; + uint8 _attack; + + bool _evpUpdate, _cont; + + int _evpUpdateCnt; + uint8 _outN; + int _nTick; + + int32 *_tlTable; + int32 *_tleTable; + + const uint32 _tickLength; + uint32 _timer; + + struct Channel { + int tick; + uint8 smp; + uint8 out; + + uint8 frqL; + uint8 frqH; + uint8 vol; + } _channels[3]; + + uint8 _noiseGenerator; + uint8 _chanEnable; + + uint8 *const *_reg; + + bool _ready; +}; + +class TownsPC98_OpnPercussionSource { +public: + TownsPC98_OpnPercussionSource(const uint32 timerbase); + ~TownsPC98_OpnPercussionSource() {} + + void init(const uint8 *instrData = 0); + void reset(); + void writeReg(uint8 address, uint8 value); + + void nextTick(int32 *buffer, uint32 bufferSize); + +private: + struct RhtChannel { + const uint8 *data; + + const uint8 *start; + const uint8 *end; + const uint8 *pos; + uint32 size; + bool active; + uint8 level; + + int8 decState; + uint8 decStep; + + int16 samples[2]; + int out; + + uint8 startPosH; + uint8 startPosL; + uint8 endPosH; + uint8 endPosL; + }; + + void recalcOuput(RhtChannel *ins); + void advanceInput(RhtChannel *ins); + + RhtChannel _rhChan[6]; + + uint8 _totalLevel; + + const uint32 _tickLength; + uint32 _timer; + + uint8 *const *_reg; + + bool _ready; +}; + +class TownsPC98_OpnCore : public Audio::AudioStream { public: enum OpnType { OD_TOWNS, @@ -1452,21 +1590,13 @@ public: OD_TYPE86 }; - TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type); - ~TownsPC98_OpnDriver(); - - bool init(); - void loadData(uint8 *data, bool loadPaused = false); - void reset(); - void fadeOut(); - - void pause() { _playing = false; } - void cont() { _playing = true; } + TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type); + virtual ~TownsPC98_OpnCore(); - void callback(); - void nextTick(int16 *buffer, uint32 bufferSize); + virtual bool init(); + virtual void reset(); - bool looping() { return _looping == _updateChannelsFlag ? true : false; } + void writeReg(uint8 part, uint8 regAddress, uint8 value); // AudioStream interface int inline readBuffer(int16 *buffer, const int numSamples); @@ -1477,24 +1607,34 @@ public: protected: void generateTables(); - TownsPC98_OpnChannel **_channels; - TownsPC98_OpnChannelSSG **_ssgChannels; - //TownsPC98_OpnChannel *_adpcmChannel; - - void setTempo(uint8 tempo); + void toggleRegProtection(bool prot) { _regProtectionFlag = prot; } + uint8 readSSGStatus() { return _ssg->chanEnable(); } - void lock() { _mutex.lock(); } - void unlock() { _mutex.unlock(); } + virtual void timerCallbackA() = 0; + virtual void timerCallbackB() = 0; - Audio::Mixer *_mixer; - Common::Mutex _mutex; - Audio::SoundHandle _soundHandle; + const int _numChan; + const int _numSSG; + const bool _hasPercussion; - const uint8 *_opnCarrier; - const uint8 *_opnFreqTable; - const uint8 *_opnFxCmdLen; - const uint8 *_opnLvlPresets; +private: + void nextTick(int32 *buffer, uint32 bufferSize); + void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); + + struct ChanInternal { + uint16 frqTemp; + bool enableLeft; + bool enableRight; + bool updateEnvelopeParameters; + int32 feedbuf[3]; + uint8 algorithm; + TownsPC98_OpnOperator **opr; + }; + TownsPC98_OpnSquareSineSource *_ssg; + TownsPC98_OpnPercussionSource *_prc; + ChanInternal *_chanInternal; + uint8 *_oprRates; uint8 *_oprRateshift; uint8 *_oprAttackDecay; @@ -1503,34 +1643,112 @@ protected: int32 *_oprLevelOut; int32 *_oprDetune; - uint8 *_trackData; + bool _regProtectionFlag; + + typedef void (TownsPC98_OpnCore::*OpnTimerProc)(); + + struct OpnTimer { + bool enabled; + uint16 value; + + int32 smpTillCb; + uint32 smpTillCbRem; + int32 smpPerCb; + uint32 smpPerCbRem; + + OpnTimerProc cb; + }; + + OpnTimer _timers[2]; + + const float _baserate; + uint32 _timerbase; + + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle; + + static const uint8 _percussionData[]; + static const uint32 _adtStat[]; + static const uint8 _detSrc[]; + static const int _ssgTables[]; + + bool _ready; +}; + +class TownsPC98_OpnDriver : public TownsPC98_OpnCore { +friend class TownsPC98_OpnChannel; +friend class TownsPC98_OpnChannelSSG; +friend class TownsPC98_OpnSfxChannel; +friend class TownsPC98_OpnChannelPCM; +public: + TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type); + ~TownsPC98_OpnDriver(); + + void loadMusicData(uint8 *data, bool loadPaused = false); + void loadSoundEffectData(uint8 *data, uint8 trackNum); + bool init(); + void reset(); + + void fadeStep(); + + void pause() { _musicPlaying = false; } + void cont() { _musicPlaying = true; } + + void timerCallbackB(); + void timerCallbackA(); + + bool looping() { return _looping == _updateChannelsFlag ? true : false; } + bool musicPlaying() { return _musicPlaying; } + +protected: + void startSoundEffect(); + + void setMusicTempo(uint8 tempo); + void setSfxTempo(uint16 tempo); + + void lock() { _mutex.lock(); } + void unlock() { _mutex.unlock(); } + + TownsPC98_OpnChannel **_channels; + TownsPC98_OpnChannelSSG **_ssgChannels; + TownsPC98_OpnSfxChannel **_sfxChannels; + TownsPC98_OpnChannelPCM *_rhythmChannel; + + Common::Mutex _mutex; + + const uint8 *_opnCarrier; + const uint8 *_opnFreqTable; + const uint8 *_opnFreqTableSSG; + const uint8 *_opnFxCmdLen; + const uint8 *_opnLvlPresets; + + uint8 *_musicBuffer; + uint8 *_sfxBuffer; + uint8 *_trackPtr; uint8 *_patches; + uint8 *_ssgPatches; - uint8 _cbCounter; uint8 _updateChannelsFlag; + uint8 _updateSSGFlag; + uint8 _updateRhythmFlag; + uint8 _updateSfxFlag; uint8 _finishedChannelsFlag; - uint16 _tempo; - bool _playing; - bool _fading; - uint8 _looping; - uint32 _tickCounter; - - bool _updateEnvelopes; - int _ssgFlag; + uint8 _finishedSSGFlag; + uint8 _finishedRhythmFlag; + uint8 _finishedSfxFlag; - int32 _samplesTillCallback; - int32 _samplesTillCallbackRemainder; - int32 _samplesPerCallback; - int32 _samplesPerCallbackRemainder; + bool _musicPlaying; + bool _sfxPlaying; + uint8 _fading; + uint8 _looping; + uint32 _musicTickCounter; - const int _numChan; - const int _numSSG; - const bool _hasADPCM; - const bool _hasStereo; + int _sfxOffs; + uint8 *_sfxData; + uint16 _sfxOffsets[2]; - double _baserate; static const uint8 _drvTables[]; - static const uint32 _adtStat[]; + bool _ready; }; @@ -1538,33 +1756,20 @@ TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 re uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), _part(prt), _idFlag(id) { - _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0; - _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0; + _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0; + _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0; + _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0; _frqLSB = 0; - _protect = _updateEnvelopes = false; - _enableLeft = _enableRight = true; - _dataPtr = 0; - _ptchWhlModInitVal = _ptchWhlModCurVal = 0; - frequency = _frqTemp = 0; - memset(&_feedbuf, 0, sizeof(int) * 3); - _opr = 0; + _hold = false; + _dataPtr = 0; + _vbrModInitVal = _vbrModCurVal = 0; + _frequency = 0; } TownsPC98_OpnChannel::~TownsPC98_OpnChannel() { - if (_opr) { - for (int i = 0; i < 4; i++) - delete _opr[i]; - delete [] _opr; - } } void TownsPC98_OpnChannel::init() { - - _opr = new TownsPC98_OpnOperator*[4]; - for (int i = 0; i < 4; i++) - _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, - _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); - #define Control(x) &TownsPC98_OpnChannel::control_##x static const ControlEventFunc ctrlEvents[] = { Control(f0_setPatch), @@ -1574,8 +1779,8 @@ void TownsPC98_OpnChannel::init() { Control(f4_setOutputLevel), Control(f5_setTempo), Control(f6_repeatSection), - Control(f7_setupPitchWheel), - Control(f8_togglePitchWheel), + Control(f7_setupVibrato), + Control(f8_toggleVibrato), Control(dummy), Control(fa_writeReg), Control(fb_incOutLevel), @@ -1592,20 +1797,24 @@ void TownsPC98_OpnChannel::init() { void TownsPC98_OpnChannel::keyOff() { // all operators off uint8 value = _keyNum & 0x0f; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); _flags |= CHS_KEYOFF; } void TownsPC98_OpnChannel::keyOn() { // all operators on uint8 value = _keyNum | 0xf0; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); } void TownsPC98_OpnChannel::loadData(uint8 *data) { - _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT; + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; _ticksLeft = 1; _dataPtr = data; _totalLevel = 0x7F; @@ -1645,13 +1854,13 @@ void TownsPC98_OpnChannel::processEvents() { if (_flags & CHS_EOT) return; - if (_protect == false && _ticksLeft == _keyOffTime) + if (!_hold && _ticksLeft == _keyOffTime) keyOff(); if (--_ticksLeft) return; - if (_protect == false) + if (!_hold) keyOff(); uint8 cmd = 0; @@ -1669,14 +1878,14 @@ void TownsPC98_OpnChannel::processEvents() { if (cmd == 0x80) { keyOff(); - _protect = false; + _hold = false; } else { keyOn(); - if (_protect == false || cmd != _frqBlockMSB) + if (_hold == false || cmd != _frqBlockMSB) _flags |= CHS_RECALCFREQ; - - _protect = (para & 0x80) ? true : false; + + _hold = (para & 0x80) ? true : false; _frqBlockMSB = cmd; } @@ -1685,37 +1894,47 @@ void TownsPC98_OpnChannel::processEvents() { void TownsPC98_OpnChannel::processFrequency() { if (_flags & CHS_RECALCFREQ) { - uint8 block = (_frqBlockMSB & 0x70) >> 1; - uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; - frequency = (bfreq + _frqLSB) | (block << 8); - - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + + _frequency = (((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8); - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - if (_flags & CHS_KEYOFF) { - _ptchWhlModCurVal = _ptchWhlModInitVal; - _ptchWhlCurDelay += _ptchWhlInitDelayLo; - } + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); - _ptchWhlDurLeft = (_ptchWhlDuration >> 1); - _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + setupVibrato(); } - if (!(_flags & CHS_PITCHWHEELOFF)) { - if (--_ptchWhlCurDelay) + if (!(_flags & CHS_VBROFF)) { + if (!processVibrato()) return; - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - frequency += _ptchWhlModCurVal; - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); + } +} - if(!--_ptchWhlDurLeft) { - _ptchWhlDurLeft = _ptchWhlDuration; - _ptchWhlModCurVal = -_ptchWhlModCurVal; - } +void TownsPC98_OpnChannel::setupVibrato() { + _vbrCurDelay = _vbrInitDelayHi; + if (_flags & CHS_KEYOFF) { + _vbrModCurVal = _vbrModInitVal; + _vbrCurDelay += _vbrInitDelayLo; + } + _vbrDurLeft = (_vbrDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +} + +bool TownsPC98_OpnChannel::processVibrato() { + if (--_vbrCurDelay) + return false; + + _vbrCurDelay = _vbrInitDelayHi; + _frequency += _vbrModCurVal; + + if(!--_vbrDurLeft) { + _vbrDurLeft = _vbrDuration; + _vbrModCurVal = -_vbrModCurVal; } + + return true; } bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) { @@ -1729,7 +1948,7 @@ void TownsPC98_OpnChannel::setOutputLevel() { for (int i = 0; i < 4; i++) { if (outopr & 1) - writeReg(reg, _totalLevel); + _drv->writeReg(_part, reg, _totalLevel); outopr >>= 1; reg += 4; } @@ -1743,254 +1962,59 @@ void TownsPC98_OpnChannel::fadeStep() { } void TownsPC98_OpnChannel::reset() { - for (int i = 0; i < 4; i++) - _opr[i]->reset(); - - _updateEnvelopes = false; - _enableLeft = _enableRight = true; - memset(&_feedbuf, 0, sizeof(int) * 3); -} - -void TownsPC98_OpnChannel::updateEnv() { - for (int i = 0; i < 4 ; i++) - _opr[i]->updatePhaseIncrement(); -} + _hold = false; + _keyOffTime = 0; + _ticksLeft = 1; -void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) { - int phbuf1, phbuf2, output; - phbuf1 = phbuf2 = output = 0; + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; - switch (_algorithm) { - case 0: - _opr[0]->generateOutput(0, feed, phbuf1); - _opr[2]->generateOutput(*del, 0, phbuf2); - *del = 0; - _opr[1]->generateOutput(phbuf1, 0, *del); - _opr[3]->generateOutput(phbuf2, 0, output); - break; - case 1: - _opr[0]->generateOutput(0, feed, phbuf1); - _opr[2]->generateOutput(*del, 0, phbuf2); - _opr[1]->generateOutput(0, 0, phbuf1); - _opr[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 2: - _opr[0]->generateOutput(0, feed, phbuf2); - _opr[2]->generateOutput(*del, 0, phbuf2); - _opr[1]->generateOutput(0, 0, phbuf1); - _opr[3]->generateOutput(phbuf2, 0, output); - *del = phbuf1; - break; - case 3: - _opr[0]->generateOutput(0, feed, phbuf2); - _opr[2]->generateOutput(0, 0, *del); - _opr[1]->generateOutput(phbuf2, 0, phbuf1); - _opr[3]->generateOutput(*del, 0, output); - *del = phbuf1; - break; - case 4: - _opr[0]->generateOutput(0, feed, phbuf1); - _opr[2]->generateOutput(0, 0, phbuf2); - _opr[1]->generateOutput(phbuf1, 0, output); - _opr[3]->generateOutput(phbuf2, 0, output); - *del = 0; - break; - case 5: - *del = feed[1]; - _opr[0]->generateOutput(-1, feed, phbuf1); - _opr[2]->generateOutput(*del, 0, output); - _opr[1]->generateOutput(*del, 0, output); - _opr[3]->generateOutput(*del, 0, output); - break; - case 6: - _opr[0]->generateOutput(0, feed, phbuf1); - _opr[2]->generateOutput(0, 0, output); - _opr[1]->generateOutput(phbuf1, 0, output); - _opr[3]->generateOutput(0, 0, output); - *del = 0; - break; - case 7: - _opr[0]->generateOutput(0, feed, output); - _opr[2]->generateOutput(0, 0, output); - _opr[1]->generateOutput(0, 0, output); - _opr[3]->generateOutput(0, 0, output); - *del = 0; - break; - }; - - if (_enableLeft) { - int l = output + leftSample; - if (l > 32767) - l = 32767; - if (l < -32767) - l = -32767; - leftSample = (int16) l; - } - - if (_enableRight) { - int r = output + rightSample; - if (r > 32767) - r = 32767; - if (r < -32767) - r = -32767; - rightSample = (int16) r; - } -} + _totalLevel = 0; + _algorithm = 0; + _flags = CHS_EOT; + _algorithm = 0; + + _block = 0; + _frequency = 0; + _frqBlockMSB = 0; + _frqLSB = 0; -void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) { - uint8 h = regAdress & 0xf0; - uint8 l = (regAdress & 0x0f); - static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; - uint8 o = oprOrdr[(l - _regOffset) >> 2]; + _ssgTl = 0; + _ssgStartLvl = 0; + _ssgTargetLvl = 0; + _ssgStep = 0; + _ssgTicksLeft = 0; - switch (h) { - case 0x00: - // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - case 0x10: - // adpcm - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - case 0x20: - if (l == 8) { - // Key on/off - for (int i = 0; i < 4; i++) { - if ((value >> (4 + i)) & 1) - _opr[i]->keyOn(); - else - _opr[i]->keyOff(); - } - } else if (l == 2) { - // LFO - warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); - } else if (l == 7) { - // Timers; Ch 3/6 special mode - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)"); - } else if (l == 4 || l == 5) { - // Timer A - warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)"); - } else if (l == 6) { - // Timer B - warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)"); - } else if (l == 10 || l == 11) { - // DAC - warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); - } - break; - - case 0x30: - // detune, multiple - _opr[o]->detune((value >> 4) & 7); - _opr[o]->multiple(value & 0x0f); - _updateEnvelopes = true; - break; - - case 0x40: - // total level - _opr[o]->totalLevel(value & 0x7f); - break; - - case 0x50: - // rate scaling, attack rate - _opr[o]->attackRate(value & 0x1f); - if (_opr[o]->scaleRate(value >> 6)) - _updateEnvelopes = true; - break; - - case 0x60: - // first decay rate, amplitude modulation - _opr[o]->decayRate(value & 0x1f); - if (value & 0x80) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); - - break; - - case 0x70: - // secondary decay rate - _opr[o]->sustainRate(value & 0x1f); - break; - - case 0x80: - // secondary amplitude, release rate; - _opr[o]->sustainLevel(value >> 4); - _opr[o]->releaseRate(value & 0x0f); - break; - - case 0x90: - // ssg - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - - case 0xa0: - // frequency - l -= _regOffset; - if (l == 0) { - _frqTemp = (_frqTemp & 0xff00) | value; - _updateEnvelopes = true; - for (int i = 0; i < 4; i++) - _opr[i]->frequency(_frqTemp); - } else if (l == 4) { - _frqTemp = (_frqTemp & 0xff) | (value << 8); - } else if (l == 8) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } else if (l == 12) { - // Ch 3/6 special mode frq - warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); - } - break; - - case 0xb0: - l -= _regOffset; - if (l == 0) { - // feedback, _algorithm - _opr[0]->feedbackLevel((value >> 3) & 7); - _opr[1]->feedbackLevel(0); - _opr[2]->feedbackLevel(0); - _opr[3]->feedbackLevel(0); - } else if (l == 4) { - // stereo, LFO sensitivity - _enableLeft = value & 0x80 ? true : false; - _enableRight = value & 0x40 ? true : false; - uint8 ams = (value & 0x3F) >> 3; - if (ams) - warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); - uint8 fms = value & 3; - if (fms) - warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); - } - break; - - default: - warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress); - break; - } + _vbrInitDelayHi = 0; + _vbrInitDelayLo = 0; + _vbrModInitVal = 0; + _vbrDuration = 0; + _vbrCurDelay = 0; + _vbrModCurVal = 0; + _vbrDurLeft = 0; } bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { - _instrID = para; + _instr = para; uint8 reg = _regOffset + 0x80; for (int i = 0; i < 4; i++) { // set release rate for each operator - writeReg(reg, 0x0f); + _drv->writeReg(_part, reg, 0x0f); reg += 4; } - const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5); + const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5); reg = _regOffset + 0x30; // write registers 0x30 to 0x8f for (int i = 0; i < 6; i++) { - writeReg(reg, tptr[0]); + _drv->writeReg(_part, reg, tptr[0]); reg += 4; - writeReg(reg, tptr[2]); + _drv->writeReg(_part, reg, tptr[2]); reg += 4; - writeReg(reg, tptr[1]); + _drv->writeReg(_part, reg, tptr[1]); reg += 4; - writeReg(reg, tptr[3]); + _drv->writeReg(_part, reg, tptr[3]); reg += 4; tptr += 4; } @@ -1998,7 +2022,7 @@ bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) { reg = _regOffset + 0xB0; _algorithm = tptr[0] & 7; // set feedback and algorithm - writeReg(reg, tptr[0]); + _drv->writeReg(_part, reg, tptr[0]); setOutputLevel(); return true; @@ -2033,7 +2057,7 @@ bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) { } bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) { - _drv->setTempo(para); + _drv->setMusicTempo(para); return true; } @@ -2043,7 +2067,7 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { if (*_dataPtr) { // repeat section until counter has reached zero - _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2); + _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2); } else { // reset counter, advance to next section _dataPtr[0] = _dataPtr[1]; @@ -2052,35 +2076,36 @@ bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) { return true; } -bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) { - _ptchWhlInitDelayLo = _dataPtr[0]; - _ptchWhlInitDelayHi = para; - _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); - _ptchWhlDuration = _dataPtr[3]; +bool TownsPC98_OpnChannel::control_f7_setupVibrato(uint8 para) { + _vbrInitDelayHi = _dataPtr[0]; + _vbrInitDelayLo = para; + _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); + _vbrDuration = _dataPtr[3]; _dataPtr += 4; - _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ; + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ; return true; } -bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) { +bool TownsPC98_OpnChannel::control_f8_toggleVibrato(uint8 para) { if (para == 0x10) { if (*_dataPtr++) { - _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF; + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF; } else { - _flags |= CHS_PITCHWHEELOFF; + _flags |= CHS_VBROFF; } } else { - //uint8 skipChannels = para / 36; - //uint8 entry = para % 36; - //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; - ////// NOT IMPLEMENTED - //t->unnamedEntries[entry] = *_dataPtr++; + /* NOT IMPLEMENTED + uint8 skipChannels = para / 36; + uint8 entry = para % 36; + TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels]; + + t->unnamedEntries[entry] = *_dataPtr++;*/ } return true; } bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) { - writeReg(para, *_dataPtr++); + _drv->writeReg(_part, para, *_dataPtr++); return true; } @@ -2113,7 +2138,7 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) { } bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) { - uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1); + uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1); _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr; return true; } @@ -2127,7 +2152,7 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { uint16 val = READ_LE_UINT16(--_dataPtr); if (val) { // loop - _dataPtr = _drv->_trackData + val; + _dataPtr = _drv->_trackPtr + val; return true; } else { // quit parsing for active channel @@ -2139,31 +2164,248 @@ bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) { } } -bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) { - _instrID = para << 4; +TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { +} + +void TownsPC98_OpnChannelSSG::init() { + _algorithm = 0x80; + + #define Control(x) &TownsPC98_OpnChannelSSG::control_##x + static const ControlEventFunc ctrlEventsSSG[] = { + Control(f0_setInstr), + Control(f1_setTotalLevel), + Control(f2_setKeyOffTime), + Control(f3_setFreqLSB), + Control(f4_setAlgorithm), + Control(f5_setTempo), + Control(f6_repeatSection), + Control(f7_setupVibrato), + Control(f8_toggleVibrato), + Control(f9_loadCustomPatch), + Control(fa_writeReg), + Control(fb_incOutLevel), + Control(fc_decOutLevel), + Control(fd_jump), + Control(dummy), + Control(ff_endOfTrack) + }; + #undef Control + + controlEvents = ctrlEventsSSG; +} + +void TownsPC98_OpnChannelSSG::processEvents() { + if (_flags & CHS_EOT) + return; + + _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + + if (!_hold && _ticksLeft == _keyOffTime) + nextShape(); + + if (!--_ticksLeft) { + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + nextShape(); + _hold = false; + } else { + if (!_hold) { + _instr &= 0xf0; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + _ssgStartLvl = _drv->_ssgPatches[_instr + 3]; + _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; + } + + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; + } + + if (!(_flags & CHS_SSGOFF)) { + if (--_ssgTicksLeft) { + if (!_drv->_fading) + setOutputLevel(_ssgStartLvl); + return; + } + + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + + if (_drv->_ssgPatches[_instr + 1] & 0x80) { + uint8 t = _ssgStartLvl - _ssgStep; + + if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { + if (!_drv->_fading) + setOutputLevel(t); + return; + } + } else { + int t = _ssgStartLvl + _ssgStep; + uint8 p = (uint8) (t & 0xff); + + if (t < 256 && _ssgTargetLvl > p) { + if (!_drv->_fading) + setOutputLevel(p); + return; + } + } + + setOutputLevel(_ssgTargetLvl); + if (_ssgStartLvl && !(_instr & 8)){ + _instr += 4; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + } else { + _flags |= CHS_SSGOFF; + setOutputLevel(0); + } + } +} + +void TownsPC98_OpnChannelSSG::processFrequency() { + if (_algorithm & 0x40) + return; + + if (_flags & CHS_RECALCFREQ) { + _block = _frqBlockMSB >> 4; + _frequency = ((const uint16*)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + + setupVibrato(); + } + + if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) { + if (!processVibrato()) + return; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + } +} + +bool TownsPC98_OpnChannelSSG::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +void TownsPC98_OpnChannelSSG::nextShape() { + _instr = (_instr & 0xf0) + 0x0c; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; +} + +void TownsPC98_OpnChannelSSG::keyOn() { + uint8 c = 0x7b; + uint8 t = (_algorithm & 0xC0) << 1; + if (_algorithm & 0x80) + t |= 4; + + c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); + t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); + + if (!(_algorithm & 0x80)) + _drv->writeReg(_part, 6, _algorithm & 0x7f); + + uint8 e = (_drv->readSSGStatus() & c) | t; + _drv->writeReg(_part, 7, e); +} + +void TownsPC98_OpnChannelSSG::protect() { + _flags |= CHS_PROTECT; +} + +void TownsPC98_OpnChannelSSG::restore() { + _flags &= ~CHS_PROTECT; + keyOn(); + _drv->writeReg(_part, 8 + _regOffset, _ssgTl); + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); +} + +void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { + _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + TownsPC98_OpnChannel::loadData(data); + setOutputLevel(0); + _algorithm = 0x80; +} + +void TownsPC98_OpnChannelSSG::setOutputLevel(uint8 lvl) { + _ssgStartLvl = lvl; + uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; + if (newTl == _ssgTl) + return; + _ssgTl = newTl; + _drv->writeReg(_part, 8 + _regOffset, _ssgTl); +} + +void TownsPC98_OpnChannelSSG::fadeStep() { + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + setOutputLevel(_ssgStartLvl); +} + +bool TownsPC98_OpnChannelSSG::control_f0_setInstr(uint8 para) { + _instr = para << 4; para = (para >> 3) & 0x1e; if (para) return control_f4_setAlgorithm(para | 0x40); return true; } -bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f1_setTotalLevel(uint8 para) { if (!_drv->_fading) _totalLevel = para; return true; } -bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_f4_setAlgorithm(uint8 para) { _algorithm = para; return true; } -bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) { - _dataPtr += 5; +bool TownsPC98_OpnChannelSSG::control_f9_loadCustomPatch(uint8 para) { + _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4; + _drv->_ssgPatches[_instr] = *_dataPtr++; + _drv->_ssgPatches[_instr + 3] = para; + _drv->_ssgPatches[_instr + 4] = *_dataPtr++; + _drv->_ssgPatches[_instr + 6] = *_dataPtr++; + _drv->_ssgPatches[_instr + 8] = *_dataPtr++; + _drv->_ssgPatches[_instr + 12] = *_dataPtr++; return true; } -bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fb_incOutLevel(uint8 para) { _dataPtr--; if (_drv->_fading) return true; @@ -2175,7 +2417,7 @@ bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) { return true; } -bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { +bool TownsPC98_OpnChannelSSG::control_fc_decOutLevel(uint8 para) { _dataPtr--; if (_drv->_fading) return true; @@ -2186,200 +2428,513 @@ bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) { return true; } -bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) { - uint16 val = READ_LE_UINT16(--_dataPtr); - if (val) { - // loop - _dataPtr = _drv->_trackData + val; - return true; +bool TownsPC98_OpnChannelSSG::control_ff_endOfTrack(uint8 para) { + if (!_drv->_sfxOffs) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // stop parsing + if (!_drv->_fading) + setOutputLevel(0); + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedSSGFlag |= _idFlag; + } } else { - // quit parsing for active channel - --_dataPtr; + // end of sfx track - restore ssg music channel _flags |= CHS_EOT; - //_finishedChannelsFlag |= _idFlag; - keyOff(); - return false; + _drv->_finishedSfxFlag |= _idFlag; + _drv->_ssgChannels[_chanNum]->restore(); } + + return false; +} + +void TownsPC98_OpnSfxChannel::loadData(uint8 *data) { + _flags = CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _ssgTl = 0xff; + _algorithm = 0x80; } -TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs, +TownsPC98_OpnChannelPCM::TownsPC98_OpnChannelPCM(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) { } -void TownsPC98_OpnChannelSSG::init() { +void TownsPC98_OpnChannelPCM::init() { _algorithm = 0x80; - - _opr = new TownsPC98_OpnOperator*[4]; - for (int i = 0; i < 4; i++) - _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift, - _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune); - #define Control(x) &TownsPC98_OpnChannelSSG::control_##x - static const ControlEventFunc ctrlEventsSSG[] = { - Control(f0_setPatchSSG), - Control(f1_setTotalLevel), - Control(f2_setKeyOffTime), - Control(f3_setFreqLSB), - Control(f4_setOutputLevel), - Control(f5_setTempo), + #define Control(x) &TownsPC98_OpnChannelPCM::control_##x + static const ControlEventFunc ctrlEventsPCM[] = { + Control(dummy), + Control(f1_prcStart), + Control(dummy), + Control(dummy), + Control(dummy), + Control(dummy), Control(f6_repeatSection), - Control(f7_setupPitchWheel), - Control(f8_togglePitchWheel), - Control(f9_unkSSG), + Control(dummy), + Control(dummy), + Control(dummy), Control(fa_writeReg), - Control(fb_incOutLevelSSG), - Control(fc_decOutLevelSSG), - Control(fd_jump), Control(dummy), - Control(ff_endOfTrackSSG) + Control(dummy), + Control(dummy), + Control(dummy), + Control(ff_endOfTrack) }; #undef Control - controlEvents = ctrlEventsSSG; + controlEvents = ctrlEventsPCM; } -void TownsPC98_OpnChannelSSG::processEvents() { +void TownsPC98_OpnChannelPCM::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; +} + +void TownsPC98_OpnChannelPCM::processEvents() { if (_flags & CHS_EOT) return; - _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; - - if (_protect == false && _ticksLeft == _keyOffTime) - keyOff(); - if (--_ticksLeft) return; - if (_protect == false) - keyOff(); - uint8 cmd = 0; bool loop = true; while (loop) { cmd = *_dataPtr++; - if (cmd < 0xf0) + if (cmd == 0x80) { loop = false; - else if (!processControlEvent(cmd)) + } else if (cmd < 0xf0) { + _drv->writeReg(_part, 0x10, cmd); + } else if (!processControlEvent(cmd)) { return; + } } + _ticksLeft = *_dataPtr++; +} + +bool TownsPC98_OpnChannelPCM::processControlEvent(uint8 cmd) { uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} - if (cmd == 0x80) { - keyOff(); - _protect = false; +bool TownsPC98_OpnChannelPCM::control_f1_prcStart(uint8 para) { + _totalLevel = para; + _drv->writeReg(_part, 0x11, para); + return true; +} + +bool TownsPC98_OpnChannelPCM::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; } else { - keyOn(); + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedRhythmFlag |= _idFlag; + return false; + } +} - if (_protect == false || cmd != _frqBlockMSB) - _flags |= CHS_RECALCFREQ; +TownsPC98_OpnSquareSineSource::TownsPC98_OpnSquareSineSource(const uint32 timerbase) : _tlTable(0), + _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0) { + memset(_channels, 0, sizeof(Channel) * 3); - _protect = (para & 0x80) ? true : false; - _frqBlockMSB = cmd; + static uint8 *const reg [] = { + &_channels[0].frqL, + &_channels[0].frqH, + &_channels[1].frqL, + &_channels[1].frqH, + &_channels[2].frqL, + &_channels[2].frqH, + &_noiseGenerator, + &_chanEnable, + &_channels[0].vol, + &_channels[1].vol, + &_channels[2].vol, + }; + + _reg = reg; + + reset(); +} + +TownsPC98_OpnSquareSineSource::~TownsPC98_OpnSquareSineSource() { + delete [] _tlTable; + delete [] _tleTable; +} + +void TownsPC98_OpnSquareSineSource::init(const int *rsTable, const int *rseTable) { + if (_ready) { + reset(); + return; } - _ticksLeft = para & 0x7f; + delete [] _tlTable; + delete [] _tleTable; + _tlTable = new int32[16]; + _tleTable = new int32[32]; + float a, b, d; + d = 801.0f; + + for (int i = 0; i < 16; i++) { + b = 1.0f / rsTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tlTable[i] = (int32) v; + + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } - if (!(_flags & CHS_SSG)) { + for (int i = 16; i < 32; i++) { + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + _ready = true; +} + +void TownsPC98_OpnSquareSineSource::reset() { + _rand = 1; + _outN = 1; + _updateRequest = -1; + _nTick = _evpUpdateCnt = 0; + _evpTimer = 0x1f; + _pReslt = 0x1f; + _attack = 0; + _cont = false; + _evpUpdate = true; + _timer = 0; + + for (int i = 0; i < 3; i++) { + _channels[i].tick = 0; + _channels[i].smp = _channels[i].out = 0; } + + for (int i = 0; i < 14; i++) + writeReg(i, 0, true); + + writeReg(7, 0xbf, true); } -void TownsPC98_OpnChannelSSG::processFrequency() { - if (_flags & CHS_RECALCFREQ) { - uint8 block = (_frqBlockMSB & 0x70) >> 1; - uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f]; - frequency = (bfreq + _frqLSB) | (block << 8); +void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { + if (address > 10 || *_reg[address] == value) { + if ((address == 11 || address == 12 || address == 13) && value) + warning("TownsPC98_OpnSquareSineSource: unsupported reg address: %d", address); + return; + } + + if (!force) { + if (_updateRequest == 31) { + warning("TownsPC98_OpnSquareSineSource: event buffer overflow"); + _updateRequest = -1; + } + _updateRequestBuf[++_updateRequest] = value; + _updateRequestBuf[++_updateRequest] = address; + return; + } - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + *_reg[address] = value; +} + +void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + if (++_nTick >= (_noiseGenerator & 0x1f)) { + if ((_rand + 1) & 2) + _outN ^= 1; - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - if (_flags & CHS_KEYOFF) { - _ptchWhlModCurVal = _ptchWhlModInitVal; - _ptchWhlCurDelay += _ptchWhlInitDelayLo; + _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); + _nTick = 0; + } + + for (int ii = 0; ii < 3; ii++) { + if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) { + _channels[ii].tick = 0; + _channels[ii].smp ^= 1; + } + _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1)); + } + + if (_evpUpdate) { + if (++_evpUpdateCnt >= 0) { + _evpUpdateCnt = 0; + + if (--_evpTimer < 0) { + if (_cont) { + _evpTimer &= 0x1f; + } else { + _evpUpdate = false; + _evpTimer = 0; + } + } + } + } + _pReslt = _evpTimer ^ _attack; + updatesRegs(); + } + + int32 finOut = 0; + for (int ii = 0; ii < 3; ii++) { + if ((_channels[ii].vol >> 4) & 1) + finOut += _tleTable[_channels[ii].out ? _pReslt : 0]; + else + finOut += _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; } - _ptchWhlDurLeft = (_ptchWhlDuration >> 1); - _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); + finOut /= 2; + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; } +} - if (!(_flags & CHS_PITCHWHEELOFF)) { - if (--_ptchWhlCurDelay) - return; - _ptchWhlCurDelay = _ptchWhlInitDelayHi; - frequency += _ptchWhlModCurVal; +void TownsPC98_OpnSquareSineSource::updatesRegs() { + for (int i = 0; i < _updateRequest;) { + uint8 b = _updateRequestBuf[i++]; + uint8 a = _updateRequestBuf[i++]; + writeReg(a, b, true); + } + _updateRequest = -1; +} + +TownsPC98_OpnPercussionSource::TownsPC98_OpnPercussionSource(const uint32 timerbase) : + _tickLength(timerbase * 2), _timer(0), _ready(false) { + + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + static uint8 *const reg [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &_rhChan[0].startPosL, + &_rhChan[1].startPosL, + &_rhChan[2].startPosL, + &_rhChan[3].startPosL, + &_rhChan[4].startPosL, + &_rhChan[5].startPosL, + &_rhChan[0].startPosH, + &_rhChan[1].startPosH, + &_rhChan[2].startPosH, + &_rhChan[3].startPosH, + &_rhChan[4].startPosH, + &_rhChan[5].startPosH, + &_rhChan[0].endPosL, + &_rhChan[1].endPosL, + &_rhChan[2].endPosL, + &_rhChan[3].endPosL, + &_rhChan[4].endPosL, + &_rhChan[5].endPosL, + &_rhChan[0].endPosH, + &_rhChan[1].endPosH, + &_rhChan[2].endPosH, + &_rhChan[3].endPosH, + &_rhChan[4].endPosH, + &_rhChan[5].endPosH, + }; + + _reg = reg; +} + +void TownsPC98_OpnPercussionSource::init(const uint8 *instrData) { + if (_ready) { + reset(); + return; + } - writeReg(_regOffset + 0xa4, (frequency >> 8)); - writeReg(_regOffset + 0xa0, (frequency & 0xff)); + const uint8 *start = instrData; + const uint8 *pos = start; - if(!--_ptchWhlDurLeft) { - _ptchWhlDurLeft = _ptchWhlDuration; - _ptchWhlModCurVal = -_ptchWhlModCurVal; + if (instrData) { + for (int i = 0; i < 6; i++) { + _rhChan[i].data = start + READ_BE_UINT16(pos); + pos += 2; + _rhChan[i].size = READ_BE_UINT16(pos); + pos += 2; } + reset(); + _ready = true; + } else { + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + _ready = false; } } -void TownsPC98_OpnChannelSSG::keyOff() { - // all operators off - uint8 value = _keyNum & 0x0f; - uint8 regAdress = 0x28; - writeReg(regAdress, value); - _flags |= CHS_KEYOFF; -} +void TownsPC98_OpnPercussionSource::reset() { + _timer = 0; + _totalLevel = 63; -void TownsPC98_OpnChannelSSG::keyOn() { - // all operators on - uint8 value = _keyNum | 0xf0; - uint8 regAdress = 0x28; - writeReg(regAdress, value); + for (int i = 0; i < 6; i++) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start = s->data; + s->end = s->data + s->size; + s->active = false; + s->level = 0; + s->out = 0; + s->decStep = 1; + s->decState = 0; + s->samples[0] = s->samples[1] = 0; + s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0; + } } -void TownsPC98_OpnChannelSSG::loadData(uint8 *data) { - _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0; - opn_SSG_UNK(0); - TownsPC98_OpnChannel::loadData(data); - _algorithm = 0x80; +void TownsPC98_OpnPercussionSource::writeReg(uint8 address, uint8 value) { + if (!_ready) + return; + + uint8 h = address >> 4; + uint8 l = address & 15; + + if (address > 15) + *_reg[address] = value; + + if (address == 0) { + if (value & 0x80) { + //key off + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) + _rhChan[i].active = false; + } + } else { + //key on + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start; + s->active = true; + s->out = 0; + s->samples[0] = s->samples[1] = 0; + s->decStep = 1; + s->decState = 0; + } + } + } + } else if (address == 1) { + // total level + _totalLevel = (value & 63) ^ 63; + for (int i = 0; i < 6; i++) + recalcOuput(&_rhChan[i]); + } else if (!h && l & 8) { + // instrument level + l &= 7; + _rhChan[l].level = (value & 0x1f) ^ 0x1f; + recalcOuput(&_rhChan[l]); + } else if (h & 3) { + l &= 7; + if (h == 1) { + // set start offset + _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8); + } else if (h == 2) { + // set end offset + _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255; + } + } } -void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) { - _ssg1 = a; - uint16 h = (_totalLevel + 1) * a; - if ((h >> 8) == _ssg2) +void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) return; - _ssg2 = (h >> 8); - writeReg(8 + _regOffset, _ssg2); + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + for (int ii = 0; ii < 6; ii++) { + RhtChannel *s = &_rhChan[ii]; + if (s->active) { + recalcOuput(s); + if (s->decStep) { + advanceInput(s); + if (s->pos == s->end) + s->active = false; + } + s->decStep ^= 1; + } + } + } + + int32 finOut = 0; + + for (int ii = 0; ii < 6; ii++) { + if (_rhChan[ii].active) + finOut += _rhChan[ii].out; + } + + finOut *= 7; + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } } -TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : - _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0), - _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84), - _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) , - _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), - _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), - _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false), - _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), - _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { - setTempo(84); - _baserate = (486202500.0 / (double)getRate()) / 10368.0; +void TownsPC98_OpnPercussionSource::recalcOuput(RhtChannel *ins) { + uint32 s = _totalLevel + ins->level; + uint32 x = s > 62 ? 0 : (1 + (s >> 3)); + int32 y = s > 62 ? 0 : (15 - (s & 7)); + ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; } -TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { - _mixer->stopHandle(_soundHandle); +void TownsPC98_OpnPercussionSource::advanceInput(RhtChannel *ins) { + static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; - if (_channels) { - for (int i = 0; i < _numChan; i++) - delete _channels[i]; - delete [] _channels; - } + static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, + 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 + }; + + uint8 cur = (int8) *ins->pos++; - if (_ssgChannels) { - for (int i = 0; i < _numSSG; i++) - delete _ssgChannels[i]; - delete [] _ssgChannels; + for (int i = 0; i < 2; i++) { + int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; + ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); + ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48); + cur >>= 4; } +} + +TownsPC98_OpnCore::TownsPC98_OpnCore(Audio::Mixer *mixer, OpnType type) : + _mixer(mixer), + _chanInternal(0), _ssg(0), _prc(0), + _numChan(type == OD_TYPE26 ? 3 : 6), _numSSG(type == OD_TOWNS ? 0 : 3), _hasPercussion(type == OD_TYPE86 ? true : false), + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), + _baserate(55125.0f / (float)mixer->getOutputRate()), + _regProtectionFlag(false), _ready(false) { + + memset(&_timers[0], 0, sizeof(OpnTimer)); + memset(&_timers[1], 0, sizeof(OpnTimer)); + _timers[0].cb = &TownsPC98_OpnCore::timerCallbackA; + _timers[1].cb = &TownsPC98_OpnCore::timerCallbackB; + _timerbase = (uint32)(_baserate * 1000000.0f); +} + +TownsPC98_OpnCore::~TownsPC98_OpnCore() { + _mixer->stopHandle(_soundHandle); + delete _ssg; + delete _prc; + delete [] _chanInternal; delete [] _oprRates; delete [] _oprRateshift; @@ -2387,235 +2942,280 @@ TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { delete [] _oprAttackDecay; delete [] _oprSinTbl; delete [] _oprLevelOut; - delete [] _oprDetune; + delete [] _oprDetune; } -bool TownsPC98_OpnDriver::init() { +bool TownsPC98_OpnCore::init() { if (_ready) { reset(); return true; } generateTables(); + + TownsPC98_OpnOperator **opr = new TownsPC98_OpnOperator*[_numChan << 2]; + for (int i = 0; i < (_numChan << 2); i++) + opr[i] = new TownsPC98_OpnOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); - if (_channels) { - for (int i = 0; i < _numChan; i++) { - if (_channels[i]) - delete _channels[i]; - } - delete [] _channels; - } - _channels = new TownsPC98_OpnChannel*[_numChan]; + _chanInternal = new ChanInternal[_numChan]; for (int i = 0; i < _numChan; i++) { - int ii = i * 6; - _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1], - _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); - _channels[i]->init(); + memset(&_chanInternal[i], 0, sizeof(ChanInternal)); + _chanInternal[i].opr = &opr[i << 2]; } - if (_ssgChannels) { - for (int i = 0; i < _numSSG; i++) { - if (_ssgChannels[i]) - delete _ssgChannels[i]; - } - delete [] _ssgChannels; - } if (_numSSG) { - _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG]; - for (int i = 0; i < _numSSG; i++) { - int ii = i * 6; - _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], - _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); - _ssgChannels[i]->init(); - } + _ssg = new TownsPC98_OpnSquareSineSource(_timerbase); + _ssg->init(&_ssgTables[0], &_ssgTables[16]); + } + + if (_hasPercussion) { + _prc = new TownsPC98_OpnPercussionSource(_timerbase); + _prc->init(_percussionData); } _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); _ready = true; + return true; } -int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) { - memset(buffer, 0, sizeof(int16) * numSamples); - int32 samplesLeft = numSamples >> 1; - while (samplesLeft) { - if (!_samplesTillCallback) { - callback(); - _samplesTillCallback = _samplesPerCallback; - _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; - if (_samplesTillCallbackRemainder >= _tempo) { - _samplesTillCallback++; - _samplesTillCallbackRemainder -= _tempo; - } - } +void TownsPC98_OpnCore::reset() { + for (int i = 0; i < _numChan; i++) { + for (int ii = 0; ii < 4; ii++) + _chanInternal[i].opr[ii]->reset(); + memset(&_chanInternal[i].feedbuf, 0, 3); + _chanInternal[i].algorithm = 0; + _chanInternal[i].frqTemp = 0; + _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true; + _chanInternal[i].updateEnvelopeParameters = false; + } - int32 render = MIN(samplesLeft, _samplesTillCallback); - samplesLeft -= render; - _samplesTillCallback -= render; + writeReg(0, 27, 0x33); - nextTick(buffer, render); + if (_ssg) + _ssg->reset(); - for (int i = 0; i < render; ++i) { - buffer[i << 1] <<= 2; - buffer[(i << 1) + 1] <<= 2; - } - - buffer += (render << 1); - } - - return numSamples; + if (_prc) + _prc->reset(); } -void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) { - if (!_ready) { - warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); +void TownsPC98_OpnCore::writeReg(uint8 part, uint8 regAddress, uint8 value) { + if (_regProtectionFlag || !_ready) return; - } - if (!data) { - warning("TownsPC98_OpnDriver: Invalid music file data"); - return; - } - - lock(); - _trackData = data; - - reset(); + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; - uint8 *src_a = data; - - for (uint8 i = 0; i < 3; i++) { - _channels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - for (int i = 0; i < _numSSG; i++) { - _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } - - for (uint8 i = 3; i < _numChan; i++) { - _channels[i]->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } + uint8 h = regAddress & 0xf0; + uint8 l = (regAddress & 0x0f); + + ChanInternal *c = &_chanInternal[(h < 0x30) ? ((value & 3) + ((value & 4) ? 3 : 0)) : ((l & 3) + 3 * part)]; + TownsPC98_OpnOperator **co = c->opr; + TownsPC98_OpnOperator *o = (h < 0x30) ? 0 : c->opr[oprOrdr[(l - (l & 3)) >> 2]]; - if (_hasADPCM) { - //_adpcmChannel->loadData(data + READ_LE_UINT16(src_a)); - src_a += 2; - } + switch (h) { + case 0x00: + // ssg + if (_ssg) + _ssg->writeReg(regAddress, value); + break; + case 0x10: + // pcm rhythm channel + if (_prc) + _prc->writeReg(regAddress - 0x10, value); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + co[i]->keyOn(); + else + co[i]->keyOff(); + } + } else if (l == 4) { + // Timer A + _timers[0].value = (_timers[0].value & 0xff00) | value; + } else if (l == 5) { + // Timer A + _timers[0].value = (_timers[0].value & 0xff) | (value << 8); + } else if (l == 6) { + // Timer B + _timers[1].value = value & 0xff; + } else if (l == 7) { + _timers[0].enabled = (value & 1) ? 1 : 0; + _timers[1].enabled = (value & 2) ? 1 : 0; + + float spc = (float)(0x400 - _timers[0].value) / _baserate; + _timers[0].smpPerCb = (int32) spc; + _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); + + spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate; + _timers[1].smpPerCb = (int32) spc; + _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f); + + if (value & 10) { + _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCbRem = _timers[0].smpTillCbRem; + } + + if (value & 20) { + _timers[1].smpTillCb = _timers[1].smpPerCb; + _timers[1].smpTillCbRem = _timers[1].smpTillCbRem; + } + } else if (l == 2) { + // LFO + warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; - _ssgFlag = 0; + case 0x30: + // detune, multiple + o->detune((value >> 4) & 7); + o->multiple(value & 0x0f); + c->updateEnvelopeParameters = true; + break; - _patches = src_a + 4; - _cbCounter = 4; - _finishedChannelsFlag = 0; + case 0x40: + // total level + o->totalLevel(value & 0x7f); + break; - // AH 0x17 - unlock(); - _playing = (loadPaused ? false : true); -} + case 0x50: + // rate scaling, attack rate + o->attackRate(value & 0x1f); + if (o->scaleRate(value >> 6)) + c->updateEnvelopeParameters = true; + break; -void TownsPC98_OpnDriver::reset() { - for (int i = 0; i < (_numChan); i++) - _channels[i]->reset(); - for (int i = 0; i < (_numSSG); i++) - _ssgChannels[i]->reset(); + case 0x60: + // first decay rate, amplitude modulation + o->decayRate(value & 0x1f); + if (value & 0x80) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)"); + break; - _playing = _fading = false; - _looping = 0; - _tickCounter = 0; -} + case 0x70: + // secondary decay rate + o->sustainRate(value & 0x1f); + break; -void TownsPC98_OpnDriver::fadeOut() { - if (!_playing) - return; + case 0x80: + // secondary amplitude, release rate; + o->sustainLevel(value >> 4); + o->releaseRate(value & 0x0f); + break; - _fading = true; + case 0x90: + warning("TownsPC98_OpnDriver: TRYING TO SSG ENVELOPE SHAPES (NOT SUPPORTED)"); + break; - for (int i = 0; i < 20; i++) { - lock(); - uint32 dTime = _tickCounter + 2; - for (int j = 0; j < _numChan; j++) { - if (_updateChannelsFlag & _channels[j]->_idFlag) - _channels[j]->fadeStep(); - } - for (int j = 0; j < _numSSG; j++) - _ssgChannels[j]->fadeStep(); + case 0xa0: + // frequency + l &= ~3; + if (l == 0) { + c->frqTemp = (c->frqTemp & 0xff00) | value; + c->updateEnvelopeParameters = true; + for (int i = 0; i < 4; i++) + co[i]->frequency(c->frqTemp); + } else if (l == 4) { + c->frqTemp = (c->frqTemp & 0xff) | (value << 8); + } else if (l == 8) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } else if (l == 12) { + // Ch 3/6 special mode frq + warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)"); + } + break; - unlock(); + case 0xb0: + l &= ~3; + if (l == 0) { + // feedback, _algorithm + co[0]->feedbackLevel((value >> 3) & 7); + c->algorithm = value & 7; + } else if (l == 4) { + // stereo, LFO sensitivity + c->enableLeft = value & 0x80 ? true : false; + c->enableRight = value & 0x40 ? true : false; + uint8 ams = (value & 0x3F) >> 3; + if (ams) + warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)"); + uint8 fms = value & 3; + if (fms) + warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)"); + } + break; - while (_playing) { - if (_tickCounter >= dTime) - break; - } + default: + warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAddress); + break; } - - _fading = false; - - reset(); } -void TownsPC98_OpnDriver::callback() { - if (!_playing || --_cbCounter) - return; +int inline TownsPC98_OpnCore::readBuffer(int16 *buffer, const int numSamples) { + memset(buffer, 0, sizeof(int16) * numSamples); + int32 *tmp = new int32[numSamples]; + int32 *tmpStart = tmp; + memset(tmp, 0, sizeof(int32) * numSamples); + int32 samplesLeft = numSamples >> 1; - _cbCounter = 4; - _tickCounter++; + while (samplesLeft) { - lock(); + int32 render = samplesLeft; - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->_idFlag) { - _channels[i]->processEvents(); - _channels[i]->processFrequency(); - } - } + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + if (!_timers[i].smpTillCb) { + (this->*_timers[i].cb)(); + _timers[i].smpTillCb = _timers[i].smpPerCb; - if (_numSSG) { - for (int i = 0; i < _numSSG; i++) { - _ssgChannels[i]->processEvents(); - _ssgChannels[i]->processFrequency(); + _timers[i].smpTillCbRem += _timers[i].smpPerCbRem; + if (_timers[i].smpTillCbRem >= _timerbase) { + _timers[i].smpTillCb++; + _timers[i].smpTillCbRem -= _timerbase; + } + } + render = MIN(render, _timers[i].smpTillCb); + } } - } - - _ssgFlag = 0; - unlock(); + samplesLeft -= render; - if (_finishedChannelsFlag == _updateChannelsFlag) - reset(); -} + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + _timers[i].smpTillCb -= render; + } + } -void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) { - if (!_playing) - return; + nextTick(tmp, render); - for (int i = 0; i < _numChan ; i++) { - if (_channels[i]->_updateEnvelopes) { - _channels[i]->_updateEnvelopes = false; - _channels[i]->updateEnv(); - } - - for (uint32 ii = 0; ii < bufferSize ; ii++) - _channels[i]->generateOutput(buffer[ii * 2], - buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf); - } + if (_ssg) + _ssg->nextTick(tmp, render); + if (_prc) + _prc->nextTick(tmp, render); - for (int i = 0; i < _numSSG ; i++) { - if (_ssgChannels[i]->_updateEnvelopes) { - _ssgChannels[i]->_updateEnvelopes = false; - _ssgChannels[i]->updateEnv(); + for (int i = 0; i < render; ++i) { + int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767); + buffer[i << 1] = (int16) l; + int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767); + buffer[(i << 1) + 1] = (int16) r; } - - for (uint32 ii = 0; ii < bufferSize ; ii++) - _ssgChannels[i]->generateOutput(buffer[ii * 2], - buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf); + + buffer += (render << 1); + tmp += (render << 1); } + + delete [] tmpStart; + return numSamples; } -void TownsPC98_OpnDriver::generateTables() { +void TownsPC98_OpnCore::generateTables() { delete [] _oprRates; _oprRates = new uint8[128]; memset(_oprRates, 0x90, 32); @@ -2641,7 +3241,7 @@ void TownsPC98_OpnDriver::generateTables() { delete [] _oprFrq; _oprFrq = new uint32[0x1000]; for (uint32 i = 0; i < 0x1000; i++) - _oprFrq[i] = (uint32)(_baserate * (double)(i << 11)); + _oprFrq[i] = (uint32)(_baserate * (float)(i << 11)); delete [] _oprAttackDecay; _oprAttackDecay = new uint8[152]; @@ -2675,22 +3275,416 @@ void TownsPC98_OpnDriver::generateTables() { uint8 *dtt = new uint8[128]; memset(dtt, 0, 36); memset(dtt + 36, 1, 8); - memcpy(dtt + 44, _drvTables + 144, 84); + memcpy(dtt + 44, _detSrc, 84); delete [] _oprDetune; _oprDetune = new int32[256]; for (int i = 0; i < 128; i++) { - _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0); + _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); _oprDetune[i + 128] = -_oprDetune[i]; } delete [] dtt; } -void TownsPC98_OpnDriver::setTempo(uint8 tempo) { - _tempo = tempo; - _samplesPerCallback = getRate() / _tempo; - _samplesPerCallbackRemainder = getRate() % _tempo; +void TownsPC98_OpnCore::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (int i = 0; i < _numChan; i++) { + TownsPC98_OpnOperator **o = _chanInternal[i].opr; + + if (_chanInternal[i].updateEnvelopeParameters) { + _chanInternal[i].updateEnvelopeParameters = false; + for (int ii = 0; ii < 4 ; ii++) + o[ii]->updatePhaseIncrement(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) { + int32 phbuf1, phbuf2, output; + phbuf1 = phbuf2 = output = 0; + + int32 *leftSample = &buffer[ii * 2]; + int32 *rightSample = &buffer[ii * 2 + 1]; + int32 *del = &_chanInternal[i].feedbuf[2]; + int32 *feed = _chanInternal[i].feedbuf; + + switch (_chanInternal[i].algorithm) { + case 0: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + o[1]->generateOutput(phbuf1, 0, *del); + o[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(0, 0, *del); + o[1]->generateOutput(phbuf2, 0, phbuf1); + o[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, phbuf2); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf1, 0, output); + *del = phbuf1; + break; + case 6: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + o[0]->generateOutput(0, feed, output); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(0, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + int32 finOut = ((output * 7) / 2); + + if (_chanInternal[i].enableLeft) + *leftSample += finOut; + + if (_chanInternal[i].enableRight) + *rightSample += finOut; + } + } +} + +TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : TownsPC98_OpnCore(mixer, type), + _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0), + _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0), + + _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132), + _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 84)), + + _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), + _updateSSGFlag(type == OD_TOWNS ? 0x00 : 0x07), _finishedSSGFlag(0), + _updateRhythmFlag(type == OD_TYPE86 ? 0x01 : 0x00), _finishedRhythmFlag(0), + _updateSfxFlag(type == OD_TOWNS ? 0x00 : 0x06), _finishedSfxFlag(0), + + _musicTickCounter(0), + + _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { +} + +TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete [] _channels; + } + + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) + delete _ssgChannels[i]; + delete [] _ssgChannels; + } + + if (_sfxChannels) { + for (int i = 0; i < 2; i++) + delete _sfxChannels[i]; + delete [] _sfxChannels; + } + + if (_rhythmChannel) + delete _rhythmChannel; + + delete [] _ssgPatches; +} + +bool TownsPC98_OpnDriver::init() { + if (_ready) { + reset(); + return true; + } + + TownsPC98_OpnCore::init(); + + _channels = new TownsPC98_OpnChannel*[_numChan]; + for (int i = 0; i < _numChan; i++) { + int ii = i * 6; + _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _channels[i]->init(); + } + + if (_numSSG) { + _ssgPatches = new uint8[256]; + memcpy(_ssgPatches, _drvTables + 156, 256); + + _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG]; + for (int i = 0; i < _numSSG; i++) { + int ii = i * 6; + _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _ssgChannels[i]->init(); + } + + _sfxChannels = new TownsPC98_OpnSfxChannel*[2]; + for (int i = 0; i < 2; i++) { + int ii = (i + 1) * 6; + _sfxChannels[i] = new TownsPC98_OpnSfxChannel(this, _drvTables[ii], _drvTables[ii + 1], + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); + _sfxChannels[i]->init(); + } + } + + if (_hasPercussion) { + _rhythmChannel = new TownsPC98_OpnChannelPCM(this, 0, 0, 0, 0, 0, 1); + _rhythmChannel->init(); + } + + setMusicTempo(84); + setSfxTempo(654); + + _ready = true; + + return true; +} + +void TownsPC98_OpnDriver::loadMusicData(uint8 *data, bool loadPaused) { + if (!_ready) { + warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); + return; + } + + if (!data) { + warning("TownsPC98_OpnDriver: Invalid music file data"); + return; + } + + reset(); + + lock(); + + uint8 *src_a = _trackPtr = _musicBuffer = data; + + for (uint8 i = 0; i < 3; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (uint8 i = 3; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + if (_hasPercussion) { + _rhythmChannel->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + toggleRegProtection(false); + + _patches = src_a + 4; + _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0; + + _musicPlaying = (loadPaused ? false : true); + + unlock(); +} + +void TownsPC98_OpnDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { + if (!_ready) { + warning("TownsPC98_OpnDriver: Driver must be initialized before loading data"); + return; + } + + if (!_sfxChannels) { + warning("TownsPC98_OpnDriver: Sound effects not supported by this configuration"); + return; + } + + if (!data) { + warning("TownsPC98_OpnDriver: Invalid sound effects file data"); + return; + } + + lock(); + _sfxData = _sfxBuffer = data; + _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); + _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); + _sfxPlaying = true; + _finishedSfxFlag = 0; + unlock(); +} + +void TownsPC98_OpnDriver::reset() { + lock(); + + TownsPC98_OpnCore::reset(); + + for (int i = 0; i < _numChan; i++) + _channels[i]->reset(); + for (int i = 0; i < _numSSG; i++) + _ssgChannels[i]->reset(); + + if (_numSSG) { + for (int i = 0; i < 2; i++) + _sfxChannels[i]->reset(); + + memcpy(_ssgPatches, _drvTables + 156, 256); + } + + if (_rhythmChannel) + _rhythmChannel->reset(); + + _musicPlaying = false; + _sfxPlaying = false; + _fading = false; + _looping = 0; + _musicTickCounter = 0; + _sfxData = 0; + + unlock(); +} + +void TownsPC98_OpnDriver::fadeStep() { + if (!_musicPlaying) + return; + + lock(); + + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + + for (int j = 0; j < _numSSG; j++) { + if (_updateSSGFlag & _ssgChannels[j]->_idFlag) + _ssgChannels[j]->fadeStep(); + } + + if (!_fading) { + _fading = 19; + if (_hasPercussion) { + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->reset(); + } + } else { + if (!--_fading) + reset(); + } + + unlock(); +} + +void TownsPC98_OpnDriver::timerCallbackB() { + lock(); + + _sfxOffs = 0; + + if (_musicPlaying) { + _musicTickCounter++; + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + for (int i = 0; i < _numSSG; i++) { + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + + if (_hasPercussion) + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->processEvents(); + } + + toggleRegProtection(false); + + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) + _musicPlaying = false; + + unlock(); +} + +void TownsPC98_OpnDriver::timerCallbackA() { + lock(); + + if (_sfxChannels && _sfxPlaying) { + if (_sfxData) + startSoundEffect(); + + _sfxOffs = 3; + _trackPtr = _sfxBuffer; + + for (int i = 0; i < 2; i++) { + if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { + _sfxChannels[i]->processEvents(); + _sfxChannels[i]->processFrequency(); + } + } + + _trackPtr = _musicBuffer; + } + + if (_finishedSfxFlag == _updateSfxFlag) + _sfxPlaying = false; + + unlock(); +} + +void TownsPC98_OpnDriver::setMusicTempo(uint8 tempo) { + writeReg(0, 0x26, tempo); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_OpnDriver::setSfxTempo(uint16 tempo) { + writeReg(0, 0x24, tempo & 0xff); + writeReg(0, 0x25, tempo >> 8); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_OpnDriver::startSoundEffect() { + for (int i = 0; i < 2; i++) { + if (_sfxOffsets[i]) { + _ssgChannels[i + 1]->protect(); + _sfxChannels[i]->reset(); + _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); + } + } + + _sfxData = 0; } const uint8 TownsPC98_OpnDriver::_drvTables[] = { @@ -2706,55 +3700,63 @@ const uint8 TownsPC98_OpnDriver::_drvTables[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - // fmt level presets + // fmt level presets 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, - + // carriers 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, - // frequencies - 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, - 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, - 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, - 0x00, 0x00, 0x00, 0x00, - - // unused - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - - // detune - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, - 0x16, 0x16, 0x16, 0x16, - - // pc98 level presets + // pc98 level presets 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25, 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10, - 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90 -}; + 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90, -const uint32 TownsPC98_OpnDriver::_adtStat[] = { - 0x00010001, 0x00010001, 0x00010001, 0x01010001, - 0x00010101, 0x00010101, 0x00010101, 0x01010101, - 0x01010101, 0x01010101, 0x01010102, 0x01010102, - 0x01020102, 0x01020102, 0x01020202, 0x01020202, - 0x02020202, 0x02020202, 0x02020204, 0x02020204, - 0x02040204, 0x02040204, 0x02040404, 0x02040404, - 0x04040404, 0x04040404, 0x04040408, 0x04040408, - 0x04080408, 0x04080408, 0x04080808, 0x04080808, - 0x08080808, 0x08080808, 0x10101010, 0x10101010 + // frequencies + 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02, + 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03, + 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04, + + // ssg frequencies + 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C, + 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09, + 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07, + + // ssg patch data + 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00, + 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00, + 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + + 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00, + 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00, + 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00 }; SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer) @@ -2916,7 +3918,8 @@ void SoundTowns::playSoundEffect(uint8 track) { } playbackBufferSize -= 0x20; - uint32 outputRate = uint32(11025 * semitoneAndSampleRate_to_sampleStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); + + uint32 outputRate = uint32(11025 * calculatePhaseStep(note, sfxRootNoteOffs, sfxRate, 11025, 0x2000)); _currentSFX = Audio::makeLinearInputStream(sfxPlaybackBuffer, playbackBufferSize, outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -2995,7 +3998,7 @@ void SoundTowns::onTimer(void *data) { music->_parser->onTimer(); } -float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey, +float SoundTowns::calculatePhaseStep(int8 semiTone, int8 semiToneRootkey, uint32 sampleRate, uint32 outputRate, int32 pitchWheel) { if (semiTone < 0) semiTone = 0; @@ -3050,18 +4053,18 @@ bool SoundPC98::init() { void SoundPC98::playTrack(uint8 track) { if (--track >= 56) track -= 55; - + if (track == _lastTrack && _musicEnabled) return; - haltTrack(); + beginFadeOut(); char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; _musicTrackData = _vm->resource()->fileData(musicfile, 0); if (_musicEnabled) - _driver->loadData(_musicTrackData); + _driver->loadMusicData(_musicTrackData); _lastTrack = track; } @@ -3074,29 +4077,42 @@ void SoundPC98::haltTrack() { } void SoundPC98::beginFadeOut() { - _driver->fadeOut(); + if (!_driver->musicPlaying()) + return; + + for (int i = 0; i < 20; i++) { + _driver->fadeStep(); + _vm->delay(32); + } haltTrack(); } -void SoundPC98::playSoundEffect(uint8) { - /// TODO /// +void SoundPC98::playSoundEffect(uint8 track) { + if (!_sfxTrackData) + return; + + // This has been disabled for now since I don't know + // how to make up the correct track number. It probably + // needs a map. + //_driver->loadSoundEffectData(_sfxTrackData, track); } // KYRA 2 SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) : - Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { + Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) { } SoundTownsPC98_v2::~SoundTownsPC98_v2() { delete[] _musicTrackData; + delete[] _sfxTrackData; delete _driver; } bool SoundTownsPC98_v2::init() { - _driver = new TownsPC98_OpnDriver(_mixer, /*_vm->gameFlags().platform == Common::kPlatformPC98 ? - TownsPC98_OpnDriver::OD_TYPE86 :*/ TownsPC98_OpnDriver::OD_TOWNS); + _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? + TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; _vm->checkCD(); // FIXME: While checking for 'track1.XXX(X)' looks like @@ -3106,13 +4122,19 @@ bool SoundTownsPC98_v2::init() { // this misses the possibility that we play the tracks // right off CD. So we should find another way to // check if we have access to CD audio. + Resource *res = _vm->resource(); if (_musicEnabled && - (Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") || - Common::File::exists("track1.flac") || Common::File::exists("track1.fla"))) + (res->exists("track1.mp3") || res->exists("track1.ogg") || res->exists("track1.flac") || res->exists("track1.fla"))) _musicEnabled = 2; + return _driver->init(); } +void SoundTownsPC98_v2::loadSoundFile(Common::String file) { + delete [] _sfxTrackData; + _sfxTrackData = _vm->resource()->fileData(file.c_str(), 0); +} + void SoundTownsPC98_v2::process() { AudioCD.updateCD(); } @@ -3138,9 +4160,9 @@ void SoundTownsPC98_v2::playTrack(uint8 track) { char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); delete[] _musicTrackData; - + _musicTrackData = _vm->resource()->fileData(musicfile, 0); - _driver->loadData(_musicTrackData, true); + _driver->loadMusicData(_musicTrackData, true); if (_musicEnabled == 2 && trackNum != -1) { AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0); @@ -3160,7 +4182,14 @@ void SoundTownsPC98_v2::haltTrack() { } void SoundTownsPC98_v2::beginFadeOut() { - _driver->fadeOut(); + if (!_driver->musicPlaying()) + return; + + for (int i = 0; i < 20; i++) { + _driver->fadeStep(); + _vm->delay(32); + } + haltTrack(); } @@ -3221,7 +4250,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { sfx[i] = cmd; } - uint32 outputRate = uint32(11025 * SoundTowns::semitoneAndSampleRate_to_sampleStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); + uint32 outputRate = uint32(11025 * SoundTowns::calculatePhaseStep(0x3c, 0x3c, sfxRate, 11025, 0x2000)); _currentSFX = Audio::makeLinearInputStream(sfx, outsize, outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0); @@ -3233,16 +4262,163 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) { } void SoundTownsPC98_v2::playSoundEffect(uint8 track) { - if (!_useFmSfx) + if (!_useFmSfx || !_sfxTrackData) return; - uint8 *sd = _vm->resource()->fileData("sound.dat", 0); + _driver->loadSoundEffectData(_sfxTrackData, track); +} + +// static resources + +const uint32 TownsPC98_OpnCore::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; +const uint8 TownsPC98_OpnCore::_detSrc[] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16 +}; - //TODO +const int TownsPC98_OpnCore::_ssgTables[] = { + 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, + 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, + 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, + 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, + 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, + 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB +}; - delete [] sd; -} +const uint8 TownsPC98_OpnCore::_percussionData[] = { + 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57, + 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141, + 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139, + 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37, + 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137, + 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33, + 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139, + 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24, + 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144, + 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216, + 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201, + 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128, + 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33, + 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163, + 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249, + 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178, + 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148, + 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161, + 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32, + 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176, + 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140, + 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243, + 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144, + 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129, + 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56, + 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0, + 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58, + 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10, + 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8, + 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179, + 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153, + 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76, + 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193, + 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136, + 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181, + 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11, + 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184, + 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136, + 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180, + 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200, + 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10, + 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49, + 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242, + 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138, + 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171, + 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211, + 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56, + 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0, + 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61, + 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169, + 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243, + 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31, + 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160, + 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9, + 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16, + 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106, + 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144, + 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58, + 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72, + 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136, + 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161, + 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57, + 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147, + 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59, + 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25, + 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24, + 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178, + 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129, + 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63, + 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29, + 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184, + 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159, + 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153, + 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61, + 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220, + 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128, + 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145, + 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130, + 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8, + 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138, + 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176, + 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143, + 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177, + 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18, + 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59, + 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146, + 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0, + 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179, + 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122, + 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226, + 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134, + 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203, + 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151, + 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37, + 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18, + 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62, + 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231, + 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25, + 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60, + 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146, + 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119, + 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172, + 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34, + 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187, + 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21, + 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154, + 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169, + 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41, + 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83, + 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181, + 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73, + 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8 +}; } // end of namespace Kyra diff --git a/engines/kyra/sprites.cpp b/engines/kyra/sprites.cpp index 34c2986f25..05074d20b1 100644 --- a/engines/kyra/sprites.cpp +++ b/engines/kyra/sprites.cpp @@ -28,7 +28,6 @@ #include "common/stream.h" #include "common/util.h" #include "common/system.h" -#include "common/events.h" #include "kyra/screen.h" #include "kyra/kyra_lok.h" #include "kyra/sprites.h" diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index bb63c24c36..bfffefb70a 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -43,22 +43,22 @@ namespace Kyra { -#define RESFILE_VERSION 31 +#define RESFILE_VERSION 32 -bool StaticResource::checkKyraDat() { - Common::File kyraDat; - if (!kyraDat.open(StaticResource::staticDataFilename())) +bool StaticResource::checkKyraDat(Resource *res) { + Common::SharedPtr<Common::SeekableReadStream> kyraDat(res->getFileStream(StaticResource::staticDataFilename())); + if (!kyraDat) return false; - uint32 size = kyraDat.size() - 16; + uint32 size = kyraDat->size() - 16; uint8 digest[16]; - kyraDat.seek(size, SEEK_SET); - if (kyraDat.read(digest, 16) != 16) + kyraDat->seek(size, SEEK_SET); + if (kyraDat->read(digest, 16) != 16) return false; - kyraDat.close(); uint8 digestCalc[16]; - if (!Common::md5_file(StaticResource::staticDataFilename().c_str(), digestCalc, size)) + kyraDat->seek(0, SEEK_SET); + if (!Common::md5_file(*kyraDat, digestCalc, size)) return false; for (int i = 0; i < 16; ++i) @@ -308,28 +308,27 @@ bool StaticResource::init() { } char errorBuffer[100]; - int tempSize = 0; - uint8 *temp = getFile("INDEX", tempSize); - if (!temp) { + Common::SeekableReadStream *index = getFile("INDEX"); + if (!index) { snprintf(errorBuffer, sizeof(errorBuffer), "is missing an '%s' entry", getFilename("INDEX")); outputError(errorBuffer); return false; } - if (tempSize != 3*4) { - delete[] temp; + if (index->size() != 3*4) { + delete index; snprintf(errorBuffer, sizeof(errorBuffer), "has incorrect header size for entry '%s'", getFilename("INDEX")); outputError(errorBuffer); return false; } - uint32 version = READ_BE_UINT32(temp); - uint32 gameID = READ_BE_UINT32((temp+4)); - uint32 featuresValue = READ_BE_UINT32((temp+8)); + uint32 version = index->readUint32BE(); + uint32 gameID = index->readUint32BE(); + uint32 featuresValue = index->readUint32BE(); - delete[] temp; - temp = 0; + delete index; + index = 0; if (version != RESFILE_VERSION) { snprintf(errorBuffer, sizeof(errorBuffer), "has invalid version %d required, you got %d", RESFILE_VERSION, version); @@ -553,82 +552,86 @@ bool StaticResource::loadLanguageTable(const char *filename, void *&ptr, int &si } bool StaticResource::loadStringTable(const char *filename, void *&ptr, int &size) { - uint8 *filePtr = getFile(filename, size); - if (!filePtr) + Common::SeekableReadStream *file = getFile(filename); + if (!file) return false; - uint8 *src = filePtr; - uint32 count = READ_BE_UINT32(src); src += 4; + uint32 count = file->readUint32BE(); size = count; char **output = new char*[count]; assert(output); - const char *curPos = (const char*)src; for (uint32 i = 0; i < count; ++i) { - int strLen = strlen(curPos); - output[i] = new char[strLen+1]; - assert(output[i]); - memcpy(output[i], curPos, strLen+1); - curPos += strLen+1; + Common::String string; + char c = 0; + while ((c = (char)file->readByte()) != 0) + string += c; + + output[i] = new char[string.size()+1]; + strcpy(output[i], string.c_str()); } - delete[] filePtr; + delete file; ptr = output; return true; } bool StaticResource::loadRawData(const char *filename, void *&ptr, int &size) { - ptr = getFile(filename, size); - if (!ptr) + Common::SeekableReadStream *file = getFile(filename); + if (!file) return false; + + ptr = new uint8[file->size()]; + file->read(ptr, file->size()); + size = file->size(); + delete file; + return true; } bool StaticResource::loadShapeTable(const char *filename, void *&ptr, int &size) { - uint8 *filePtr = getFile(filename, size); - if (!filePtr) + Common::SeekableReadStream *file = getFile(filename); + if (!file) return false; - uint8 *src = filePtr; - uint32 count = READ_BE_UINT32(src); src += 4; + uint32 count = file->readUint32BE(); size = count; Shape *loadTo = new Shape[count]; assert(loadTo); for (uint32 i = 0; i < count; ++i) { - loadTo[i].imageIndex = *src++; - loadTo[i].x = *src++; - loadTo[i].y = *src++; - loadTo[i].w = *src++; - loadTo[i].h = *src++; - loadTo[i].xOffset = *src++; - loadTo[i].yOffset = *src++; + loadTo[i].imageIndex = file->readByte(); + loadTo[i].x = file->readByte(); + loadTo[i].y = file->readByte(); + loadTo[i].w = file->readByte(); + loadTo[i].h = file->readByte(); + loadTo[i].xOffset = file->readSByte(); + loadTo[i].yOffset = file->readSByte(); } - delete[] filePtr; + delete file; ptr = loadTo; return true; } bool StaticResource::loadRoomTable(const char *filename, void *&ptr, int &size) { - uint8 *filePtr = getFile(filename, size); - if (!filePtr) + Common::SeekableReadStream *file = getFile(filename); + if (!file) return false; - uint8 *src = filePtr; - uint32 count = READ_BE_UINT32(src); src += 4; + uint32 count = file->readUint32BE(); size = count; Room *loadTo = new Room[count]; assert(loadTo); for (uint32 i = 0; i < count; ++i) { - loadTo[i].nameIndex = *src++; - loadTo[i].northExit = READ_BE_UINT16(src); src += 2; - loadTo[i].eastExit = READ_BE_UINT16(src); src += 2; - loadTo[i].southExit = READ_BE_UINT16(src); src += 2; - loadTo[i].westExit = READ_BE_UINT16(src); src += 2; + loadTo[i].nameIndex = file->readByte(); + loadTo[i].northExit = file->readUint16BE(); + loadTo[i].eastExit = file->readUint16BE(); + loadTo[i].southExit = file->readUint16BE(); + loadTo[i].westExit = file->readUint16BE(); memset(&loadTo[i].itemsTable[0], 0xFF, sizeof(byte)*6); memset(&loadTo[i].itemsTable[6], 0, sizeof(byte)*6); memset(loadTo[i].itemsXPos, 0, sizeof(uint16)*12); @@ -636,7 +639,7 @@ bool StaticResource::loadRoomTable(const char *filename, void *&ptr, int &size) memset(loadTo[i].needInit, 0, sizeof(loadTo[i].needInit)); } - delete[] filePtr; + delete file; ptr = loadTo; return true; @@ -651,10 +654,10 @@ bool StaticResource::loadPaletteTable(const char *filename, void *&ptr, int &siz ++temp; int end = atoi(temp); - char **table = new char*[end-start+1]; + uint8 **table = new uint8*[end-start+1]; assert(table); - char file[64]; + char baseFilename[64]; temp = filename; temp = strstr(temp, " "); ++temp; @@ -662,16 +665,24 @@ bool StaticResource::loadPaletteTable(const char *filename, void *&ptr, int &siz if (temp == NULL) return false; ++temp; - strncpy(file, temp, 64); + strncpy(baseFilename, temp, 64); char name[64]; for (int i = start; i <= end; ++i) { - snprintf(name, 64, "%s%d.PAL", file, i); - table[(start != 0) ? (i-start) : i] = (char*)getFile(name, size); - if (!table[(start != 0) ? (i-start) : i]) { + snprintf(name, 64, "%s%d.PAL", baseFilename, i); + + Common::SeekableReadStream *file = getFile(name); + if (!file) { + for (int j = start; j < i; ++i) + delete[] table[j-start]; delete[] table; + return false; } + + table[i-start] = new uint8[file->size()]; + file->read(table[i-start], file->size()); + delete file; } ptr = table; @@ -680,86 +691,67 @@ bool StaticResource::loadPaletteTable(const char *filename, void *&ptr, int &siz } bool StaticResource::loadHofSequenceData(const char *filename, void *&ptr, int &size) { - int filesize; - uint8 *filePtr = getFile(filename, filesize); + Common::SeekableReadStream *file = getFile(filename); - if (!filePtr) + if (!file) return false; - uint16 *hdr = (uint16 *) filePtr; - int numSeq = READ_BE_UINT16(hdr++); + int numSeq = file->readUint16BE(); + uint32 offset = 2; Sequence *tmp_s = new Sequence[numSeq]; - char *tmp_c = 0; size = sizeof(HofSeqData) + numSeq * (sizeof(Sequence) + 28); for (int i = 0; i < numSeq; i++) { - const uint8 *offset = (const uint8 *)(filePtr + READ_BE_UINT16(hdr++)); - tmp_s[i].flags = READ_BE_UINT16(offset); - offset += 2; - tmp_c = new char[14]; - memcpy(tmp_c, offset, 14); - tmp_s[i].wsaFile = tmp_c; - offset += 14; - tmp_c = new char[14]; - memcpy(tmp_c, offset, 14); - tmp_s[i].cpsFile = tmp_c; - offset += 14; - tmp_s[i].startupCommand = *offset++; - tmp_s[i].finalCommand = *offset++; - tmp_s[i].stringIndex1 = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].stringIndex2 = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].startFrame = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].numFrames = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].frameDelay = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].xPos = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].yPos = READ_BE_UINT16(offset); - offset += 2; - tmp_s[i].duration = READ_BE_UINT16(offset); + file->seek(offset, SEEK_SET); offset += 2; + file->seek(file->readUint16BE(), SEEK_SET); + + tmp_s[i].flags = file->readUint16BE(); + tmp_s[i].wsaFile = new char[14]; + file->read(const_cast<char*>(tmp_s[i].wsaFile), 14); + tmp_s[i].cpsFile = new char[14]; + file->read(const_cast<char*>(tmp_s[i].cpsFile), 14); + tmp_s[i].startupCommand = file->readByte(); + tmp_s[i].finalCommand = file->readByte(); + tmp_s[i].stringIndex1 = file->readUint16BE(); + tmp_s[i].stringIndex2 = file->readUint16BE(); + tmp_s[i].startFrame = file->readUint16BE(); + tmp_s[i].numFrames = file->readUint16BE(); + tmp_s[i].frameDelay = file->readUint16BE(); + tmp_s[i].xPos = file->readUint16BE(); + tmp_s[i].yPos = file->readUint16BE(); + tmp_s[i].duration = file->readUint16BE(); } - int numSeqN = READ_BE_UINT16(hdr++); + file->seek(offset, SEEK_SET); offset += 2; + int numSeqN = file->readUint16BE(); NestedSequence *tmp_n = new NestedSequence[numSeqN]; size += (numSeqN * (sizeof(NestedSequence) + 14)); for (int i = 0; i < numSeqN; i++) { - const uint8 *offset = (const uint8 *)(filePtr + READ_BE_UINT16(hdr++)); - tmp_n[i].flags = READ_BE_UINT16(offset); - offset += 2; - tmp_c = new char[14]; - memcpy(tmp_c, offset, 14); - tmp_n[i].wsaFile = tmp_c; - offset += 14; - tmp_n[i].startframe = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].endFrame = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].frameDelay = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].x = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].y = READ_BE_UINT16(offset); - offset += 2; - uint16 ctrlOffs = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].startupCommand = READ_BE_UINT16(offset); - offset += 2; - tmp_n[i].finalCommand = READ_BE_UINT16(offset); + file->seek(offset, SEEK_SET); offset += 2; + file->seek(file->readUint16BE(), SEEK_SET); + + tmp_n[i].flags = file->readUint16BE(); + tmp_n[i].wsaFile = new char[14]; + file->read(const_cast<char*>(tmp_n[i].wsaFile), 14); + tmp_n[i].startframe = file->readUint16BE(); + tmp_n[i].endFrame = file->readUint16BE(); + tmp_n[i].frameDelay = file->readUint16BE(); + tmp_n[i].x = file->readUint16BE(); + tmp_n[i].y = file->readUint16BE(); + uint16 ctrlOffs = file->readUint16BE(); + tmp_n[i].startupCommand = file->readUint16BE(); + tmp_n[i].finalCommand = file->readUint16BE(); if (ctrlOffs) { - int num_c = *(filePtr + ctrlOffs); - const uint16 *in_c = (uint16*) (filePtr + ctrlOffs + 1); + file->seek(ctrlOffs, SEEK_SET); + int num_c = file->readByte(); FrameControl *tmp_f = new FrameControl[num_c]; for (int ii = 0; ii < num_c; ii++) { - tmp_f[ii].index = READ_BE_UINT16(in_c++); - tmp_f[ii].delay = READ_BE_UINT16(in_c++); + tmp_f[ii].index = file->readUint16BE(); + tmp_f[ii].delay = file->readUint16BE(); } tmp_n[i].wsaControl = (const FrameControl*) tmp_f; @@ -770,7 +762,7 @@ bool StaticResource::loadHofSequenceData(const char *filename, void *&ptr, int & } } - delete[] filePtr; + delete file; HofSeqData *loadTo = new HofSeqData; assert(loadTo); @@ -786,65 +778,53 @@ bool StaticResource::loadHofSequenceData(const char *filename, void *&ptr, int & } bool StaticResource::loadShapeAnimData_v1(const char *filename, void *&ptr, int &size) { - int filesize; - uint8 *filePtr = getFile(filename, filesize); - uint8 *src = filePtr; + Common::SeekableReadStream *file = getFile(filename); - if (!filePtr) + if (!file) return false; - size = *src++; + size = file->readByte(); ItemAnimData_v1 *loadTo = new ItemAnimData_v1[size]; assert(loadTo); for (int i = 0; i < size; i++) { - loadTo[i].itemIndex = (int16) READ_BE_UINT16(src); - src += 2; - loadTo[i].y = READ_BE_UINT16(src); - src += 2; + loadTo[i].itemIndex = file->readSint16BE(); + loadTo[i].y = file->readUint16BE(); uint16 *tmp_f = new uint16[20]; - for (int ii = 0; ii < 20; ii++) { - tmp_f[ii] = READ_BE_UINT16(src); - src += 2; - } + for (int ii = 0; ii < 20; ii++) + tmp_f[ii] = file->readUint16BE(); loadTo[i].frames = tmp_f; } - delete[] filePtr; + delete file; ptr = loadTo; return true; } bool StaticResource::loadShapeAnimData_v2(const char *filename, void *&ptr, int &size) { - int filesize; - uint8 *filePtr = getFile(filename, filesize); - uint8 *src = filePtr; + Common::SeekableReadStream *file = getFile(filename); - if (!filePtr) + if (!file) return false; - size = *src++; + size = file->readByte(); ItemAnimData_v2 *loadTo = new ItemAnimData_v2[size]; assert(loadTo); for (int i = 0; i < size; i++) { - loadTo[i].itemIndex = (int16) READ_BE_UINT16(src); - src += 2; - loadTo[i].numFrames = *src++; + loadTo[i].itemIndex = file->readSint16BE(); + loadTo[i].numFrames = file->readByte(); FrameControl *tmp_f = new FrameControl[loadTo[i].numFrames]; for (int ii = 0; ii < loadTo[i].numFrames; ii++) { - tmp_f[ii].index = READ_BE_UINT16(src); - src += 2; - tmp_f[ii].delay = READ_BE_UINT16(src); - src += 2; + tmp_f[ii].index = file->readUint16BE(); + tmp_f[ii].delay = file->readUint16BE(); } loadTo[i].frames = tmp_f; } - delete[] filePtr; + delete file; ptr = loadTo; - return true; } @@ -920,6 +900,7 @@ void StaticResource::freePaletteTable(void *&ptr, int &size) { uint8 **data = (uint8**)ptr; while (size--) delete[] data[size]; + delete[] data; ptr = 0; size = 0; } @@ -948,11 +929,8 @@ const char *StaticResource::getFilename(const char *name) { return filename.c_str(); } -uint8 *StaticResource::getFile(const char *name, int &size) { - uint32 tempSize = 0; - uint8 *data = _vm->resource()->fileData(getFilename(name), &tempSize); - size = tempSize; - return data; +Common::SeekableReadStream *StaticResource::getFile(const char *name) { + return _vm->resource()->getFileStream(getFilename(name)); } #pragma mark - diff --git a/engines/kyra/text.cpp b/engines/kyra/text.cpp index f8eb10a85e..eecb617942 100644 --- a/engines/kyra/text.cpp +++ b/engines/kyra/text.cpp @@ -29,7 +29,6 @@ #include "kyra/screen.h" #include "kyra/text.h" -#include "common/events.h" #include "common/system.h" #include "common/endian.h" diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp index dd587c5112..b94b8a6258 100644 --- a/engines/kyra/text_hof.cpp +++ b/engines/kyra/text_hof.cpp @@ -335,7 +335,7 @@ void KyraEngine_HoF::objectChatWaitToFinish() { const uint32 endTime = _chatEndTime; resetSkipFlag(); - while (running && !_quitFlag) { + while (running && !quit()) { if (!_emc->isValid(&_chatScriptState)) _emc->start(&_chatScriptState, 1); @@ -353,7 +353,7 @@ void KyraEngine_HoF::objectChatWaitToFinish() { uint32 nextFrame = _system->getMillis() + delayTime * _tickLength; - while (_system->getMillis() < nextFrame && !_quitFlag) { + while (_system->getMillis() < nextFrame && !quit()) { updateWithText(); const uint32 curTime = _system->getMillis(); @@ -593,7 +593,7 @@ void KyraEngine_HoF::initTalkObject(int index) { if (_currentTalkSections.STATim) { _tim->resetFinishedFlag(); - while (!_quitFlag && !_tim->finished()) { + while (!quit() && !_tim->finished()) { _tim->exec(_currentTalkSections.STATim, false); if (_chatText) updateWithText(); @@ -609,7 +609,7 @@ void KyraEngine_HoF::deinitTalkObject(int index) { if (_currentTalkSections.ENDTim) { _tim->resetFinishedFlag(); - while (!_quitFlag && !_tim->finished()) { + while (!quit() && !_tim->finished()) { _tim->exec(_currentTalkSections.ENDTim, false); if (_chatText) updateWithText(); @@ -647,10 +647,10 @@ void KyraEngine_HoF::npcChatSequence(const char *str, int objectId, int vocHigh, _chatVocHigh = _chatVocLow = -1; } - while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(_quitFlag || skipFlag())) { + while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(quit() || skipFlag())) { if ((!speechEnabled() && chatAnimEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) { _tim->resetFinishedFlag(); - while (!_tim->finished() && !skipFlag() && !_quitFlag) { + while (!_tim->finished() && !skipFlag() && !quit()) { if (_currentTalkSections.TLKTim) _tim->exec(_currentTalkSections.TLKTim, false); else diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp index f6b0407a75..150ec59a23 100644 --- a/engines/kyra/text_lok.cpp +++ b/engines/kyra/text_lok.cpp @@ -120,8 +120,8 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const if (event.kbd.keycode == '.') _skipFlag = true; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - quitGame(); runLoop = false; break; case Common::EVENT_LBUTTONDOWN: diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp index 16c56da099..be306ceec1 100644 --- a/engines/kyra/text_mr.cpp +++ b/engines/kyra/text_mr.cpp @@ -349,7 +349,7 @@ void KyraEngine_MR::objectChatWaitToFinish() { const uint32 endTime = _chatEndTime; resetSkipFlag(); - while (running && !_quitFlag) { + while (running && !quit()) { if (!_emc->isValid(&_chatScriptState)) _emc->start(&_chatScriptState, 1); @@ -367,7 +367,7 @@ void KyraEngine_MR::objectChatWaitToFinish() { uint32 nextFrame = _system->getMillis() + delayTime * _tickLength; - while (_system->getMillis() < nextFrame && !_quitFlag) { + while (_system->getMillis() < nextFrame && !quit()) { updateWithText(); const uint32 curTime = _system->getMillis(); @@ -419,7 +419,7 @@ void KyraEngine_MR::badConscienceChatWaitToFinish() { uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength; int frame = _badConscienceFrameTable[_badConscienceAnim+24]; - while (running && !_quitFlag) { + while (running && !quit()) { if (nextFrame < _system->getMillis()) { ++frame; if (_badConscienceFrameTable[_badConscienceAnim+32] < frame) @@ -477,7 +477,7 @@ void KyraEngine_MR::goodConscienceChatWaitToFinish() { uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength; int frame = _goodConscienceFrameTable[_goodConscienceAnim+15]; - while (running && !_quitFlag) { + while (running && !quit()) { if (nextFrame < _system->getMillis()) { ++frame; if (_goodConscienceFrameTable[_goodConscienceAnim+20] < frame) @@ -597,7 +597,7 @@ void KyraEngine_MR::albumChatWaitToFinish() { uint32 nextFrame = 0; int frame = 12; - while (running && !_quitFlag) { + while (running && !quit()) { if (nextFrame < _system->getMillis()) { ++frame; if (frame > 22) diff --git a/engines/kyra/timer_mr.cpp b/engines/kyra/timer_mr.cpp index 37a910ccf2..dd749723ce 100644 --- a/engines/kyra/timer_mr.cpp +++ b/engines/kyra/timer_mr.cpp @@ -65,7 +65,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) { void KyraEngine_MR::timerFleaDeath(int arg) { debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg); _timer->setCountdown(4, 5400); - saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME"); + saveGame(getSavegameFilename(999), "Autosave", 0); _screen->hideMouse(); _timer->disable(4); runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1); diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp index 3d18f27c7e..0f6440fd47 100644 --- a/engines/kyra/vqa.cpp +++ b/engines/kyra/vqa.cpp @@ -32,13 +32,13 @@ // The jung2.vqa movie does work, but only thanks to a grotesque hack. -#include "common/events.h" #include "common/system.h" #include "sound/audiostream.h" #include "sound/mixer.h" #include "kyra/sound.h" #include "kyra/screen.h" #include "kyra/vqa.h" +#include "kyra/resource.h" namespace Kyra { @@ -91,10 +91,10 @@ uint32 VQAMovie::readTag() { // Some tags have to be on an even offset, so they are padded with a // zero byte. Skip that. - uint32 tag = _file.readUint32BE(); + uint32 tag = _file->readUint32BE(); if (!(tag & 0xFF000000)) { - tag = (tag << 8) | _file.readByte(); + tag = (tag << 8) | _file->readByte(); } return tag; @@ -185,18 +185,19 @@ bool VQAMovie::open(const char *filename) { debugC(9, kDebugLevelMovie, "VQAMovie::open('%s')", filename); close(); - if (!_file.open(filename)) + _file = _vm->resource()->getFileStream(filename); + if (!_file) return false; - if (_file.readUint32BE() != MKID_BE('FORM')) { + if (_file->readUint32BE() != MKID_BE('FORM')) { warning("VQAMovie::open: Cannot find `FORM' tag"); return false; } // For now, we ignore the size of the FORM chunk. - _file.readUint32BE(); + _file->readUint32BE(); - if (_file.readUint32BE() != MKID_BE('WVQA')) { + if (_file->readUint32BE() != MKID_BE('WVQA')) { warning("WQAMovie::open: Cannot find `WVQA' tag"); return false; } @@ -209,30 +210,30 @@ bool VQAMovie::open(const char *filename) { while (!foundHeader || !foundFrameInfo) { uint32 tag = readTag(); - uint32 size = _file.readUint32BE(); + uint32 size = _file->readUint32BE(); switch (tag) { case MKID_BE('VQHD'): // VQA header - _header.version = _file.readUint16LE(); - _header.flags = _file.readUint16LE(); - _header.numFrames = _file.readUint16LE(); - _header.width = _file.readUint16LE(); - _header.height = _file.readUint16LE(); - _header.blockW = _file.readByte(); - _header.blockH = _file.readByte(); - _header.frameRate = _file.readByte(); - _header.cbParts = _file.readByte(); - _header.colors = _file.readUint16LE(); - _header.maxBlocks = _file.readUint16LE(); - _header.unk1 = _file.readUint32LE(); - _header.unk2 = _file.readUint16LE(); - _header.freq = _file.readUint16LE(); - _header.channels = _file.readByte(); - _header.bits = _file.readByte(); - _header.unk3 = _file.readUint32LE(); - _header.unk4 = _file.readUint16LE(); - _header.maxCBFZSize = _file.readUint32LE(); - _header.unk5 = _file.readUint32LE(); + _header.version = _file->readUint16LE(); + _header.flags = _file->readUint16LE(); + _header.numFrames = _file->readUint16LE(); + _header.width = _file->readUint16LE(); + _header.height = _file->readUint16LE(); + _header.blockW = _file->readByte(); + _header.blockH = _file->readByte(); + _header.frameRate = _file->readByte(); + _header.cbParts = _file->readByte(); + _header.colors = _file->readUint16LE(); + _header.maxBlocks = _file->readUint16LE(); + _header.unk1 = _file->readUint32LE(); + _header.unk2 = _file->readUint16LE(); + _header.freq = _file->readUint16LE(); + _header.channels = _file->readByte(); + _header.bits = _file->readByte(); + _header.unk3 = _file->readUint32LE(); + _header.unk4 = _file->readUint16LE(); + _header.maxCBFZSize = _file->readUint32LE(); + _header.unk5 = _file->readUint32LE(); // Kyrandia 3 uses version 1 VQA files, and is the only // known game to do so. This version of the format has @@ -302,7 +303,7 @@ bool VQAMovie::open(const char *filename) { foundFrameInfo = true; for (int i = 0; i < _header.numFrames; i++) { - _frameInfo[i] = 2 * _file.readUint32LE(); + _frameInfo[i] = 2 * _file->readUint32LE(); } // HACK: This flag is set in jung2.vqa, and its @@ -318,31 +319,31 @@ bool VQAMovie::open(const char *filename) { // to the first VQFR chunk. if (_frameInfo[0] & 0x01000000) { - uint32 oldPos = _file.pos(); + uint32 oldPos = _file->pos(); while (1) { uint32 scanTag = readTag(); - uint32 scanSize = _file.readUint32BE(); + uint32 scanSize = _file->readUint32BE(); - if (_file.eof()) + if (_file->eos()) break; if (scanTag == MKID_BE('VQFR')) { - _frameInfo[0] = (_file.pos() - 8) | 0x80000000; + _frameInfo[0] = (_file->pos() - 8) | 0x80000000; break; } - _file.seek(scanSize, SEEK_CUR); + _file->seek(scanSize, SEEK_CUR); } - _file.seek(oldPos); + _file->seek(oldPos); } break; default: warning("VQAMovie::open: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; } } @@ -373,8 +374,8 @@ void VQAMovie::close() { _vectorPointers = NULL; _stream = NULL; - if (_file.isOpen()) - _file.close(); + delete _file; + _file = 0; freeBuffers(); @@ -391,13 +392,13 @@ void VQAMovie::displayFrame(uint frameNum) { bool foundFrame = false; uint i; - _file.seek(_frameInfo[frameNum] & 0x7FFFFFFF); + _file->seek(_frameInfo[frameNum] & 0x7FFFFFFF); while (!foundSound || !foundFrame) { uint32 tag = readTag(); - uint32 size = _file.readUint32BE(); + uint32 size = _file->readUint32BE(); - if (_file.eof()) { + if (_file->eos()) { // This happens at the last frame. Apparently it has // no sound? break; @@ -405,24 +406,24 @@ void VQAMovie::displayFrame(uint frameNum) { byte *inbuf, *outbuf; uint32 insize, outsize; - uint32 end; + int32 end; switch (tag) { case MKID_BE('SND0'): // Uncompressed sound foundSound = true; inbuf = new byte[size]; - _file.read(inbuf, size); + _file->read(inbuf, size); assert(_stream); _stream->queueBuffer(inbuf, size); break; case MKID_BE('SND1'): // Compressed sound, almost like AUD foundSound = true; - outsize = _file.readUint16LE(); - insize = _file.readUint16LE(); + outsize = _file->readUint16LE(); + insize = _file->readUint16LE(); inbuf = new byte[insize]; - _file.read(inbuf, insize); + _file->read(inbuf, insize); if (insize == outsize) { assert(_stream); @@ -439,50 +440,50 @@ void VQAMovie::displayFrame(uint frameNum) { case MKID_BE('SND2'): // Compressed sound foundSound = true; warning("VQAMovie::displayFrame: `SND2' is not implemented"); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; case MKID_BE('VQFR'): foundFrame = true; - end = _file.pos() + size - 8; + end = _file->pos() + size - 8; - while (_file.pos() < end) { + while (_file->pos() < end) { tag = readTag(); - size = _file.readUint32BE(); + size = _file->readUint32BE(); switch (tag) { case MKID_BE('CBF0'): // Full codebook - _file.read(_codeBook, size); + _file->read(_codeBook, size); break; case MKID_BE('CBFZ'): // Full codebook inbuf = (byte *)allocBuffer(0, size); - _file.read(inbuf, size); + _file->read(inbuf, size); Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize); break; case MKID_BE('CBP0'): // Partial codebook _compressedCodeBook = false; - _file.read(_partialCodeBook + _partialCodeBookSize, size); + _file->read(_partialCodeBook + _partialCodeBookSize, size); _partialCodeBookSize += size; _numPartialCodeBooks++; break; case MKID_BE('CBPZ'): // Partial codebook _compressedCodeBook = true; - _file.read(_partialCodeBook + _partialCodeBookSize, size); + _file->read(_partialCodeBook + _partialCodeBookSize, size); _partialCodeBookSize += size; _numPartialCodeBooks++; break; case MKID_BE('CPL0'): // Palette assert(size <= 3 * 256); - _file.read(_vm->screen()->_currentPalette, size); + _file->read(_vm->screen()->_currentPalette, size); break; case MKID_BE('CPLZ'): // Palette inbuf = (byte *)allocBuffer(0, size); - _file.read(inbuf, size); + _file->read(inbuf, size); Screen::decodeFrame4(inbuf, _vm->screen()->_currentPalette, 768); break; @@ -490,14 +491,14 @@ void VQAMovie::displayFrame(uint frameNum) { assert(size / 2 <= _numVectorPointers); for (i = 0; i < size / 2; i++) - _vectorPointers[i] = _file.readUint16LE(); + _vectorPointers[i] = _file->readUint16LE(); break; case MKID_BE('VPTZ'): // Frame data inbuf = (byte *)allocBuffer(0, size); outbuf = (byte *)allocBuffer(1, 2 * _numVectorPointers); - _file.read(inbuf, size); + _file->read(inbuf, size); size = Screen::decodeFrame4(inbuf, outbuf, 2 * _numVectorPointers); assert(size / 2 <= _numVectorPointers); @@ -508,7 +509,7 @@ void VQAMovie::displayFrame(uint frameNum) { default: warning("VQAMovie::displayFrame: Unknown `VQFR' sub-tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; } @@ -518,7 +519,7 @@ void VQAMovie::displayFrame(uint frameNum) { default: warning("VQAMovie::displayFrame: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; } } @@ -593,11 +594,11 @@ void VQAMovie::play() { uint32 insize, outsize; if (_stream) { - while (_file.pos() < (_frameInfo[0] & 0x7FFFFFFF)) { + while ((uint)_file->pos() < (_frameInfo[0] & 0x7FFFFFFF)) { uint32 tag = readTag(); - uint32 size = _file.readUint32BE(); + uint32 size = _file->readUint32BE(); - if (_file.eof()) { + if (_file->eos()) { warning("VQAMovie::play: Unexpected EOF"); break; } @@ -605,16 +606,16 @@ void VQAMovie::play() { switch (tag) { case MKID_BE('SND0'): // Uncompressed sound inbuf = new byte[size]; - _file.read(inbuf, size); + _file->read(inbuf, size); _stream->queueBuffer(inbuf, size); break; case MKID_BE('SND1'): // Compressed sound - outsize = _file.readUint16LE(); - insize = _file.readUint16LE(); + outsize = _file->readUint16LE(); + insize = _file->readUint16LE(); inbuf = new byte[insize]; - _file.read(inbuf, insize); + _file->read(inbuf, insize); if (insize == outsize) { _stream->queueBuffer(inbuf, insize); @@ -628,17 +629,17 @@ void VQAMovie::play() { case MKID_BE('SND2'): // Compressed sound warning("VQAMovie::play: `SND2' is not implemented"); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; case MKID_BE('CMDS'): // Unused tag, always empty in kyra3 debugC(9, kDebugLevelMovie, "VQAMovie::play: skipping CMDS tag"); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; default: warning("VQAMovie::play: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF)); - _file.seek(size, SEEK_CUR); + _file->seek(size, SEEK_CUR); break; } } @@ -671,8 +672,8 @@ void VQAMovie::play() { if (event.kbd.ascii == 27) return; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->quitGame(); return; default: break; diff --git a/engines/kyra/vqa.h b/engines/kyra/vqa.h index f600f008b7..46d3bd48fb 100644 --- a/engines/kyra/vqa.h +++ b/engines/kyra/vqa.h @@ -26,6 +26,8 @@ #ifndef KYRA_VQA_H #define KYRA_VQA_H +#include "common/stream.h" + class OSystem; namespace Kyra { @@ -98,7 +100,7 @@ protected: void displayFrame(uint frameNum); - Common::File _file; + Common::SeekableReadStream *_file; VQAHeader _header; uint32 *_frameInfo; diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp index 2af02b0374..f9f53b2806 100644 --- a/engines/lure/animseq.cpp +++ b/engines/lure/animseq.cpp @@ -44,12 +44,18 @@ AnimAbortType AnimationSequence::delay(uint32 milliseconds) { while (g_system->getMillis() < delayCtr) { while (events.pollEvent()) { if ((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) { - if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) return ABORT_END_INTRO; - else return ABORT_NEXT_SCENE; - } else if (events.type() == Common::EVENT_LBUTTONDOWN) + if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) + return ABORT_END_INTRO; + else + return ABORT_NEXT_SCENE; + } else if (events.type() == Common::EVENT_LBUTTONDOWN) { return ABORT_NEXT_SCENE; - else if (events.type() == Common::EVENT_QUIT) + } else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) { return ABORT_END_INTRO; + } else if (events.type() == Common::EVENT_MAINMENU) { + return ABORT_NONE; + } + } uint32 delayAmount = delayCtr - g_system->getMillis(); diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp index 7dd1c77348..163d095243 100644 --- a/engines/lure/detection.cpp +++ b/engines/lure/detection.cpp @@ -26,6 +26,7 @@ #include "base/plugins.h" #include "common/advancedDetector.h" +#include "common/savefile.h" #include "lure/lure.h" @@ -184,9 +185,20 @@ public: return "Lure of the Temptress (C) Revolution"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; }; +bool LureMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + bool LureMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Lure::LureGameDescription *gd = (const Lure::LureGameDescription *)desc; if (gd) { @@ -195,6 +207,44 @@ bool LureMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common return gd != 0; } +SaveStateList LureMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + Common::String saveDesc; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + saveDesc = Lure::getSaveName(in); + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); + delete in; + } + } + } + + return saveList; +} + +void LureMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".%03d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + #if PLUGIN_ENABLED_DYNAMIC(LURE) REGISTER_PLUGIN_DYNAMIC(LURE, PLUGIN_TYPE_ENGINE, LureMetaEngine); #else diff --git a/engines/lure/events.cpp b/engines/lure/events.cpp index 30e0e571b7..e244f69097 100644 --- a/engines/lure/events.cpp +++ b/engines/lure/events.cpp @@ -29,6 +29,7 @@ #include "graphics/cursorman.h" #include "lure/events.h" +#include "lure/lure.h" #include "lure/res.h" namespace Lure { @@ -137,11 +138,12 @@ void Mouse::setPosition(int newX, int newY) { void Mouse::waitForRelease() { Events &e = Events::getReference(); + LureEngine &engine = LureEngine::getReference(); do { - while (e.pollEvent() && !e.quitFlag) ; + while (e.pollEvent() && !engine.quit()) ; g_system->delayMillis(20); - } while (!e.quitFlag && (lButton() || rButton() || mButton())); + } while (!engine.quit() && (lButton() || rButton() || mButton())); } /*--------------------------------------------------------------------------*/ @@ -150,7 +152,6 @@ static Events *int_events = NULL; Events::Events() { int_events = this; - quitFlag = false; } Events &Events::getReference() { @@ -163,10 +164,6 @@ bool Events::pollEvent() { // Handle keypress switch (_event.type) { - case Common::EVENT_QUIT: - quitFlag = true; - break; - case Common::EVENT_LBUTTONDOWN: case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONDOWN: @@ -190,7 +187,7 @@ void Events::waitForPress() { bool keyButton = false; while (!keyButton) { while (pollEvent()) { - if (_event.type == Common::EVENT_QUIT) return; + if ((_event.type == Common::EVENT_QUIT) || (_event.type == Common::EVENT_RTL)) return; else if ((_event.type == Common::EVENT_KEYDOWN) && (_event.kbd.ascii != 0)) keyButton = true; else if ((_event.type == Common::EVENT_LBUTTONDOWN) || @@ -210,10 +207,11 @@ void Events::waitForPress() { bool Events::interruptableDelay(uint32 milliseconds) { Events &events = Events::getReference(); + LureEngine &engine = LureEngine::getReference(); uint32 delayCtr = g_system->getMillis() + milliseconds; while (g_system->getMillis() < delayCtr) { - if (events.quitFlag) return true; + if (engine.quit()) return true; if (events.pollEvent()) { if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) || diff --git a/engines/lure/events.h b/engines/lure/events.h index d1246f95d8..f04072aa0f 100644 --- a/engines/lure/events.h +++ b/engines/lure/events.h @@ -66,8 +66,6 @@ class Events { private: Common::Event _event; public: - bool quitFlag; - Events(); static Events &getReference(); diff --git a/engines/lure/fights.cpp b/engines/lure/fights.cpp index dcf09ba50d..51fce850e6 100644 --- a/engines/lure/fights.cpp +++ b/engines/lure/fights.cpp @@ -22,6 +22,7 @@ #include "lure/fights.h" #include "lure/luredefs.h" #include "lure/game.h" +#include "lure/lure.h" #include "lure/res.h" #include "lure/room.h" #include "lure/sound.h" @@ -108,15 +109,15 @@ bool FightsManager::isFighting() { } void FightsManager::fightLoop() { + LureEngine &engine = LureEngine::getReference(); Resources &res = Resources::getReference(); Game &game = Game::getReference(); Room &room = Room::getReference(); - Events &events = Events::getReference(); FighterRecord &playerFight = getDetails(PLAYER_ID); uint32 timerVal = g_system->getMillis(); // Loop for the duration of the battle - while (!events.quitFlag && (playerFight.fwhits != GENERAL_MAGIC_ID)) { + while (!engine.quit() && (playerFight.fwhits != GENERAL_MAGIC_ID)) { checkEvents(); if (g_system->getMillis() > timerVal + GAME_FRAME_DELAY) { @@ -184,6 +185,7 @@ const KeyMapping keyList[] = { {Common::KEYCODE_INVALID, 0}}; void FightsManager::checkEvents() { + LureEngine &engine = LureEngine::getReference(); Game &game = Game::getReference(); Events &events = Events::getReference(); Mouse &mouse = Mouse::getReference(); @@ -196,7 +198,7 @@ void FightsManager::checkEvents() { if (events.type() == Common::EVENT_KEYDOWN) { switch (events.event().kbd.keycode) { case Common::KEYCODE_ESCAPE: - events.quitFlag = true; + engine.quitGame(); return; case Common::KEYCODE_d: diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp index f9b31c21c5..479877f229 100644 --- a/engines/lure/game.cpp +++ b/engines/lure/game.cpp @@ -23,10 +23,10 @@ * */ -#include "lure/lure.h" #include "lure/game.h" #include "lure/animseq.h" #include "lure/fights.h" +#include "lure/lure.h" #include "lure/res_struct.h" #include "lure/room.h" #include "lure/scripts.h" @@ -125,6 +125,7 @@ void Game::nextFrame() { void Game::execute() { OSystem &system = *g_system; + LureEngine &engine = LureEngine::getReference(); Room &room = Room::getReference(); Resources &res = Resources::getReference(); Events &events = Events::getReference(); @@ -137,12 +138,20 @@ void Game::execute() { screen.empty(); screen.setPaletteEmpty(); + + bool _loadSavegame = false; + + if (engine.gameToLoad() != -1) + _loadSavegame = engine.loadGame(engine.gameToLoad()); + + if (!_loadSavegame) { + // Flag for starting game + setState(GS_RESTART); + } - // Flag for starting game - setState(GS_RESTART); bool initialRestart = true; - while (!events.quitFlag) { + while (!engine.quit()) { if ((_state & GS_RESTART) != 0) { res.reset(); @@ -162,7 +171,7 @@ void Game::execute() { mouse.cursorOn(); // Main game loop - while (!events.quitFlag && ((_state & GS_RESTART) == 0)) { + while (!engine.quit() && ((_state & GS_RESTART) == 0)) { // If time for next frame, allow everything to update if (system.getMillis() > timerVal + GAME_FRAME_DELAY) { timerVal = system.getMillis(); @@ -291,10 +300,7 @@ void Game::execute() { if (restartFlag) setState(GS_RESTART); - - } else if ((_state & GS_RESTART) == 0) - // Exiting game - events.quitFlag = true; + } } } @@ -892,7 +898,7 @@ void Game::doShowCredits() { void Game::doQuit() { Sound.pause(); if (getYN()) - Events::getReference().quitFlag = true; + LureEngine::getReference().quitGame(); Sound.resume(); } @@ -977,6 +983,7 @@ bool Game::getYN() { Events &events = Events::getReference(); Screen &screen = Screen::getReference(); Resources &res = Resources::getReference(); + LureEngine &engine = LureEngine::getReference(); Common::Language l = LureEngine::getReference().getLanguage(); Common::KeyCode y = Common::KEYCODE_y; @@ -1018,7 +1025,7 @@ bool Game::getYN() { } g_system->delayMillis(10); - } while (!events.quitFlag && !breakFlag); + } while (!engine.quit() && !breakFlag); screen.update(); if (!vKbdFlag) diff --git a/engines/lure/game.h b/engines/lure/game.h index 5054074fb2..06dcee750f 100644 --- a/engines/lure/game.h +++ b/engines/lure/game.h @@ -27,6 +27,7 @@ #define LURE_GAME_H +#include "common/config-manager.h" #include "engines/engine.h" #include "lure/luredefs.h" #include "lure/menu.h" @@ -85,8 +86,8 @@ public: bool &debugFlag() { return _debugFlag; } bool fastTextFlag() { return _fastTextFlag; } bool soundFlag() { return _soundFlag; } - uint8 sfxVolume() { return _sfxVolume; } - uint8 musicVolume() { return _musicVolume; } + uint8 sfxVolume() { return ConfMan.getInt("sfx_volume"); } + uint8 musicVolume() { return ConfMan.getInt("music_volume"); } Debugger &debugger() { return *_debugger; } // Menu item support methods diff --git a/engines/lure/intro.cpp b/engines/lure/intro.cpp index 4d3e172dc5..b4cbf4a833 100644 --- a/engines/lure/intro.cpp +++ b/engines/lure/intro.cpp @@ -55,17 +55,18 @@ static const AnimRecord anim_screens[] = { bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize) { Screen &screen = Screen::getReference(); - Events &events = Events::getReference(); bool isEGA = LureEngine::getReference().isEGA(); screen.screen().loadScreen(screenId); screen.update(); Palette p(paletteId); + if (LureEngine::getReference().quit()) return true; + if (isEGA) screen.setPalette(&p); else screen.paletteFadeIn(&p); bool result = interruptableDelay(delaySize); - if (events.quitFlag) return true; + if (LureEngine::getReference().quit()) return true; if (!isEGA) screen.paletteFadeOut(); @@ -83,6 +84,8 @@ bool Introduction::interruptableDelay(uint32 milliseconds) { if (events.interruptableDelay(milliseconds)) { if (events.type() == Common::EVENT_KEYDOWN) return events.event().kbd.keycode == 27; + else if (LureEngine::getReference().quit()) + return true; else if (events.type() == Common::EVENT_LBUTTONDOWN) return false; } diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp index ea760ddb4f..8cd76cbc73 100644 --- a/engines/lure/lure.cpp +++ b/engines/lure/lure.cpp @@ -92,6 +92,7 @@ int LureEngine::init() { _room = new Room(); _fights = new FightsManager(); + _gameToLoad = -1; _initialised = true; return 0; } @@ -121,31 +122,38 @@ LureEngine &LureEngine::getReference() { } int LureEngine::go() { - - if (ConfMan.getBool("copy_protection")) { - CopyProtectionDialog *dialog = new CopyProtectionDialog(); - bool result = dialog->show(); - delete dialog; - if (_events->quitFlag) - return 0; - - if (!result) - error("Sorry - copy protection failed"); - } - Game *gameInstance = new Game(); + + // If requested, load a savegame instead of showing the intro + if (ConfMan.hasKey("save_slot")) { + _gameToLoad = ConfMan.getInt("save_slot"); + if (_gameToLoad < 0 || _gameToLoad > 999) + _gameToLoad = -1; + } + + if (_gameToLoad == -1) { + if (ConfMan.getBool("copy_protection")) { + CopyProtectionDialog *dialog = new CopyProtectionDialog(); + bool result = dialog->show(); + delete dialog; + if (quit()) + return 0; + + if (!result) + error("Sorry - copy protection failed"); + } - if (ConfMan.getInt("boot_param") == 0) { - // Show the introduction - Sound.loadSection(Sound.isRoland() ? ROLAND_INTRO_SOUND_RESOURCE_ID : ADLIB_INTRO_SOUND_RESOURCE_ID); - - Introduction *intro = new Introduction(); - intro->show(); - delete intro; + if (ConfMan.getInt("boot_param") == 0) { + // Show the introduction + Sound.loadSection(Sound.isRoland() ? ROLAND_INTRO_SOUND_RESOURCE_ID : ADLIB_INTRO_SOUND_RESOURCE_ID); + Introduction *intro = new Introduction(); + intro->show(); + delete intro; + } } // Play the game - if (!_events->quitFlag) { + if (!quit()) { // Play the game Sound.loadSection(Sound.isRoland() ? ROLAND_MAIN_SOUND_RESOURCE_ID : ADLIB_MAIN_SOUND_RESOURCE_ID); gameInstance->execute(); @@ -246,6 +254,10 @@ void LureEngine::GUIError(const char *msg, ...) { Engine::GUIErrorMessage(buffer); } +void LureEngine::syncSoundSettings() { + Sound.syncSounds(); +} + Common::String *LureEngine::detectSave(int slotNumber) { Common::ReadStream *f = this->_saveFileMan->openForLoading( generateSaveName(slotNumber)); @@ -274,4 +286,23 @@ Common::String *LureEngine::detectSave(int slotNumber) { return result; } +Common::String getSaveName(Common::InSaveFile *in) { + // Check for header + char saveName[MAX_DESC_SIZE]; + char buffer[5]; + in->read(&buffer[0], 5); + if (memcmp(&buffer[0], "lure", 5) == 0) { + // Check language version + in->readByte(); + in->readByte(); + char *p = saveName; + int decCtr = MAX_DESC_SIZE - 1; + while ((decCtr > 0) && ((*p++ = in->readByte()) != 0)) --decCtr; + *p = '\0'; + + } + + return Common::String(saveName); +} + } // End of namespace Lure diff --git a/engines/lure/lure.h b/engines/lure/lure.h index 1c5b40e54b..2c1a70329e 100644 --- a/engines/lure/lure.h +++ b/engines/lure/lure.h @@ -30,6 +30,7 @@ #include "common/rect.h" #include "sound/mixer.h" #include "common/file.h" +#include "common/savefile.h" #include "lure/disk.h" #include "lure/res.h" @@ -47,6 +48,7 @@ struct LureGameDescription; class LureEngine : public Engine { private: bool _initialised; + int _gameToLoad; uint8 _saveVersion; Disk *_disk; Resources *_resources; @@ -70,9 +72,11 @@ public: virtual int init(); virtual int go(); virtual void pauseEngineIntern(bool pause); + virtual void syncSoundSettings(); Disk &disk() { return *_disk; } + int gameToLoad() { return _gameToLoad; } bool loadGame(uint8 slotNumber); bool saveGame(uint8 slotNumber, Common::String &caption); Common::String *detectSave(int slotNumber); @@ -84,7 +88,7 @@ public: Common::Platform getPlatform() const; bool isEGA() const { return (getFeatures() & GF_EGA) != 0; } }; - + Common::String getSaveName(Common::InSaveFile *in); } // End of namespace Lure #endif diff --git a/engines/lure/menu.cpp b/engines/lure/menu.cpp index 0b4ef06081..562f54da20 100644 --- a/engines/lure/menu.cpp +++ b/engines/lure/menu.cpp @@ -116,6 +116,7 @@ Menu &Menu::getReference() { uint8 Menu::execute() { OSystem &system = *g_system; + LureEngine &engine = LureEngine::getReference(); Mouse &mouse = Mouse::getReference(); Events &events = Events::getReference(); Screen &screen = Screen::getReference(); @@ -130,7 +131,7 @@ uint8 Menu::execute() { while (mouse.lButton() || mouse.rButton()) { while (events.pollEvent()) { - if (events.quitFlag) return MENUITEM_NONE; + if (engine.quit()) return MENUITEM_NONE; if (mouse.y() < MENUBAR_Y_SIZE) { MenuRecord *p = getMenuAt(mouse.x()); @@ -467,6 +468,7 @@ Action PopupMenu::Show(int numEntries, Action *actions) { uint16 PopupMenu::Show(int numEntries, const char *actions[]) { if (numEntries == 0) return 0xffff; + LureEngine &engine = LureEngine::getReference(); Events &e = Events::getReference(); Mouse &mouse = Mouse::getReference(); OSystem &system = *g_system; @@ -545,7 +547,7 @@ uint16 PopupMenu::Show(int numEntries, const char *actions[]) { } while (e.pollEvent()) { - if (e.quitFlag) { + if (engine.quit()) { selectedIndex = 0xffff; goto bail_out; diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp index 7490f05b24..495f8046bb 100644 --- a/engines/lure/scripts.cpp +++ b/engines/lure/scripts.cpp @@ -26,6 +26,7 @@ #include "lure/animseq.h" #include "lure/fights.h" #include "lure/game.h" +#include "lure/lure.h" #include "lure/res.h" #include "lure/room.h" #include "lure/screen.h" @@ -190,6 +191,7 @@ void Script::addSound(uint16 soundIndex, uint16 v2, uint16 v3) { } void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) { + LureEngine &engine = LureEngine::getReference(); Screen &screen = Screen::getReference(); Mouse &mouse = Mouse::getReference(); Events &events = Events::getReference(); @@ -219,7 +221,7 @@ void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) { anim->show(); if (!events.interruptableDelay(30000)) { // No key yet pressed, so keep waiting - while (Sound.musicInterface_CheckPlaying(6) && !events.quitFlag) { + while (Sound.musicInterface_CheckPlaying(6) && !engine.quit()) { if (events.interruptableDelay(20)) break; } @@ -227,7 +229,7 @@ void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) { delete anim; screen.paletteFadeOut(); - events.quitFlag = true; + engine.quitGame(); } // Setup the pig fight in the cave diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp index 285f66e4e2..569058b282 100644 --- a/engines/lure/sound.cpp +++ b/engines/lure/sound.cpp @@ -220,10 +220,12 @@ void SoundManager::addSound(uint8 soundIndex, bool tidyFlag) { newEntry->channel = channelCtr; newEntry->numChannels = numChannels; newEntry->flags = rec.flags; + if (_isRoland) newEntry->volume = rec.volume; else /* resource volumes do not seem to work well with our adlib emu */ newEntry->volume = 240; /* 255 causes clipping with adlib */ + _activeSounds.push_back(SoundList::value_type(newEntry)); musicInterface_Play(rec.soundNumber, channelCtr, numChannels); @@ -280,6 +282,23 @@ uint8 SoundManager::descIndexOf(uint8 soundNumber) { return 0xff; // Couldn't find entry } +// Used to sync the volume for all channels with the Config Manager +// +void SoundManager::syncSounds() { + Game &game = Game::getReference(); + musicInterface_TidySounds(); + + g_system->lockMutex(_soundMutex); + MusicListIterator i; + for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) { + if ((*i)->isMusic()) + (*i)->setVolume(game.musicVolume()); + else + (*i)->setVolume(game.sfxVolume()); + } + g_system->unlockMutex(_soundMutex); +} + SoundDescResource *SoundManager::findSound(uint8 soundNumber) { debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::findSound soundNumber=%d", soundNumber); SoundListIterator i; @@ -402,9 +421,8 @@ void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, u return; bool isMusic = (soundNumber & 0x80) != 0; - uint8 volume = isMusic ? game.musicVolume() : game.sfxVolume(); - if (!game.soundFlag() || (volume == 0)) + if (!game.soundFlag()) // Don't play sounds if sound is turned off return; @@ -563,12 +581,12 @@ void SoundManager::doTimer() { /*------------------------------------------------------------------------*/ MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS], - uint8 channelNum, uint8 soundNum, bool isMusic, uint8 numChannels, void *soundData, uint32 size) { + uint8 channelNum, uint8 soundNum, bool isMus, uint8 numChannels, void *soundData, uint32 size) { _driver = driver; _channels = channels; _soundNumber = soundNum; _channelNumber = channelNum; - _isMusic = isMusic; + _isMusic = isMus; _numChannels = numChannels; _volume = 0; @@ -576,7 +594,11 @@ MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS], /* 90 is power on default for midi compliant devices */ _channels[_channelNumber + i].volume = 90; } - setVolume(240); /* 255 causes clipping with mastervol 192 and adlib */ + + if (_isMusic) + setVolume(ConfMan.getInt("music_volume")); + else + setVolume(ConfMan.getInt("sfx_volume")); _passThrough = false; diff --git a/engines/lure/sound.h b/engines/lure/sound.h index c5a31a6c28..cf5dca7e96 100644 --- a/engines/lure/sound.h +++ b/engines/lure/sound.h @@ -66,7 +66,7 @@ private: public: MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS], - uint8 channelNum, uint8 soundNum, bool isMusic, uint8 numChannels, void *soundData, uint32 size); + uint8 channelNum, uint8 soundNum, bool isMus, uint8 numChannels, void *soundData, uint32 size); ~MidiMusic(); void setVolume(int volume); int getVolume() { return _volume; } @@ -98,6 +98,7 @@ public: uint8 channelNumber() { return _channelNumber; } uint8 soundNumber() { return _soundNumber; } bool isPlaying() { return _isPlaying; } + bool isMusic() {return _isMusic; } }; class SoundManager: public Common::Singleton<SoundManager> { @@ -142,6 +143,7 @@ public: void stopSound(uint8 soundIndex); void killSound(uint8 soundNumber); void setVolume(uint8 soundNumber, uint8 volume); + void syncSounds(); void tidySounds(); uint8 descIndexOf(uint8 soundNumber); SoundDescResource *findSound(uint8 soundNumber); diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp index 64394545d1..23cc9043cf 100644 --- a/engines/lure/surface.cpp +++ b/engines/lure/surface.cpp @@ -506,6 +506,7 @@ Surface *Surface::getScreen(uint16 resourceId) { bool Surface::getString(Common::String &line, int maxSize, bool isNumeric, bool varLength, int16 x, int16 y) { OSystem &system = *g_system; + LureEngine &engine = LureEngine::getReference(); Mouse &mouse = Mouse::getReference(); Events &events = Events::getReference(); Screen &screen = Screen::getReference(); @@ -533,7 +534,7 @@ bool Surface::getString(Common::String &line, int maxSize, bool isNumeric, bool // Loop until the input string changes refreshFlag = false; while (!refreshFlag && !abortFlag) { - abortFlag = events.quitFlag; + abortFlag = engine.quit(); if (abortFlag) break; while (events.pollEvent()) { @@ -975,7 +976,7 @@ bool SaveRestoreDialog::show(bool saveDialog) { // Provide highlighting of lines to select a save slot while (!abortFlag && !(mouse.lButton() && (selectedLine != -1)) && !mouse.rButton() && !mouse.mButton()) { - abortFlag = events.quitFlag; + abortFlag = engine.quit(); if (abortFlag) break; while (events.pollEvent()) { @@ -1178,7 +1179,7 @@ bool RestartRestoreDialog::show() { // Event loop for making selection bool buttonPressed = false; - while (!events.quitFlag) { + while (!engine.quit()) { // Handle events while (events.pollEvent()) { if ((events.type() == Common::EVENT_LBUTTONDOWN) && (highlightedButton != -1)) { @@ -1230,7 +1231,7 @@ bool RestartRestoreDialog::show() { Sound.killSounds(); - if (!restartFlag && !events.quitFlag) { + if (!restartFlag && !engine.quit()) { // Need to show Restore game dialog if (!SaveRestoreDialog::show(false)) // User cancelled, so fall back on Restart @@ -1299,6 +1300,7 @@ bool CopyProtectionDialog::show() { Screen &screen = Screen::getReference(); Events &events = Events::getReference(); Common::RandomSource rnd; + LureEngine &engine = LureEngine::getReference(); screen.setPaletteEmpty(); Palette p(COPY_PROTECTION_RESOURCE_ID - 1); @@ -1349,7 +1351,7 @@ bool CopyProtectionDialog::show() { // Clear any prior try _charIndex = 0; - while (!events.quitFlag) { + while (!engine.quit()) { while (events.pollEvent() && (_charIndex < 4)) { if (events.type() == Common::EVENT_KEYDOWN) { if ((events.event().kbd.keycode == Common::KEYCODE_BACKSPACE) && (_charIndex > 0)) { @@ -1383,7 +1385,7 @@ bool CopyProtectionDialog::show() { break; } - if (events.quitFlag) + if (engine.quit()) return false; // At this point, two page numbers have been entered - validate them diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index 5b8bdab9d6..11131783e2 100644 --- a/engines/m4/converse.cpp +++ b/engines/m4/converse.cpp @@ -406,10 +406,12 @@ void Converse::loadConversation(const char *convName) { convS->read(buffer, 8); if (debugFlag) printf("Conversation name: %s\n", buffer); - while(!convS->eos()) { + while(true) { chunkPos = convS->pos(); - if (debugFlag) printf("***** Pos: %i -> ", chunkPos); chunk = convS->readUint32LE(); // read chunk + if (convS->eos()) break; + + if (debugFlag) printf("***** Pos: %i -> ", chunkPos); switch(chunk) { case CHUNK_DECL: // Declare if (debugFlag) printf("DECL chunk\n"); @@ -544,10 +546,10 @@ void Converse::loadConversation(const char *convName) { curNode, _convNodes[curNode]->entries.size() - 1); // Seek to chunk data (i.e. TEXT/MESG tag, which is usually right // after this chunk but it can be further on in conditional reply chunks - assert(data >= convS->pos()); + assert((int)data >= convS->pos()); // If the entry's data is not right after the entry, remember the position // to return to after the data is read - if (chunk == CHUNK_CRPL && data != convS->pos()) + if (chunk == CHUNK_CRPL && (int)data != convS->pos()) returnAddress = convS->pos(); convS->seek(data, SEEK_SET); } @@ -714,7 +716,7 @@ void Converse::loadConversationMads(const char *convName) { printf("Chunk 0\n"); printf("Conv stream size: %i\n", convS->size()); - while(!convS->eos()) { + while(!convS->eos()) { // FIXME (eos changed) printf("%i ", convS->readByte()); } printf("\n"); @@ -725,7 +727,7 @@ void Converse::loadConversationMads(const char *convName) { printf("Chunk 1\n"); printf("Conv stream size: %i\n", convS->size()); - while(!convS->eos()) { + while(!convS->eos()) { // FIXME (eos changed) printf("%i ", convS->readByte()); } printf("\n"); @@ -736,7 +738,7 @@ void Converse::loadConversationMads(const char *convName) { printf("Chunk 2\n"); printf("Conv stream size: %i\n", convS->size()); - while(!convS->eos()) { + while(!convS->eos()) { // FIXME (eos changed) printf("%i ", convS->readByte()); } printf("\n"); @@ -790,7 +792,7 @@ void Converse::loadConversationMads(const char *convName) { convS->read(buffer, 14); // speech file printf("Speech file: %s\n", buffer); - while(!convS->eos()) { + while(!convS->eos()) { // FIXME: eos changed printf("%i ", convS->readByte()); } printf("\n"); @@ -803,9 +805,12 @@ void Converse::loadConversationMads(const char *convName) { printf("Chunk 1: conversation nodes\n"); printf("Conv stream size: %i\n", convS->size()); - while(!convS->eos()) { + while(true) { + uint16 id = convS->readUint16LE(); + if (convS->eos()) break; + curEntry = new ConvEntry(); - curEntry->id = convS->readUint16LE(); + curEntry->id = id; curEntry->entryCount = convS->readUint16LE(); curEntry->flags = convS->readUint16LE(); if (curEntry->entryCount == 1 && curEntry->flags != 65535) { @@ -839,10 +844,13 @@ void Converse::loadConversationMads(const char *convName) { *buffer = 0; - while(!convS->eos()) { + while(true) { //if (curPos == 0) // printf("%i: Offset %i: ", _convStrings.size(), convS->pos()); - buffer[curPos++] = convS->readByte(); + uint8 b = convS->readByte(); + if (convS->eos()) break; + + buffer[curPos++] = b; if (buffer[curPos - 1] == '~') { // filter out special characters curPos--; continue; @@ -892,9 +900,12 @@ void Converse::loadConversationMads(const char *convName) { //printf("Chunk 3 - MESG chunk data\n"); //printf("Conv stream size: %i\n", convS->size()); - while(!convS->eos()) { + while(true) { + uint16 index = convS->readUint16LE(); + if (convS->eos()) break; + curMessage = new MessageEntry(); - stringIndex = convS->readUint16LE(); + stringIndex = index; stringCount = convS->readUint16LE(); *buffer = 0; //printf("Message: %i\n", _madsMessageList.size()); @@ -915,7 +926,7 @@ void Converse::loadConversationMads(const char *convName) { convS = convData.getItemStream(6); printf("Chunk 6\n"); printf("Conv stream size: %i\n", convS->size()); - /*while(!convS->eos()) { + /*while(!convS->eos()) { // FIXME (eos changed) printf("%i ", convS->readByte()); printf("%i ", convS->readByte()); printf("%i ", convS->readByte()); @@ -954,8 +965,10 @@ void Converse::readConvEntryActions(Common::SubReadStream *convS, ConvEntry *cur int messageIndex = 0; int unk = 0; - while(!convS->eos()) { + while(true) { chunk = convS->readByte(); + if (convS->eos()) break; + type = convS->readByte(); switch (chunk) { diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp index 58c68979d1..98d007f67e 100644 --- a/engines/m4/globals.cpp +++ b/engines/m4/globals.cpp @@ -295,8 +295,11 @@ void Globals::loadMadsVocab() { char buffer[30]; strcpy(buffer, ""); - while(!vocabS->eos()) { - buffer[curPos++] = vocabS->readByte(); + while(true) { + uint8 b = vocabS->readByte(); + if (vocabS->eos()) break; + + buffer[curPos++] = b; if (buffer[curPos - 1] == '\0') { // end of string, add it to the strings list _madsVocab.push_back(strdup(buffer)); @@ -315,8 +318,11 @@ void Globals::loadMadsQuotes() { char buffer[128]; strcpy(buffer, ""); - while(!quoteS->eos()) { - buffer[curPos++] = quoteS->readByte(); + while(true) { + uint8 b = quoteS->readByte(); + if (quoteS->eos()) break; + + buffer[curPos++] = b; if (buffer[curPos - 1] == '\0') { // end of string, add it to the strings list _madsQuotes.push_back(strdup(buffer)); diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index b2c0eda1ce..44d7f653d1 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -107,9 +107,9 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc) : // FIXME _vm = this; - Common::File::addDefaultDirectory(_gameDataPath); - Common::File::addDefaultDirectory("goodstuf"); - Common::File::addDefaultDirectory("resource"); + Common::File::addDefaultDirectory(_gameDataDir); + Common::File::addDefaultDirectory("goodstuf"); // FIXME: This is nonsense + Common::File::addDefaultDirectory("resource"); // FIXME: This is nonsense Common::addSpecialDebugLevel(kDebugScript, "script", "Script debug level"); Common::addSpecialDebugLevel(kDebugConversations, "conversations", "Conversations debugging"); diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index c51daa84c4..71b45ca77c 100644 --- a/engines/m4/mads_anim.cpp +++ b/engines/m4/mads_anim.cpp @@ -247,15 +247,16 @@ void TextviewView::scriptDone() { } void TextviewView::processLines() { + _script->readLine_OLD(_currentLine, 79); if (_script->eos()) error("Attempted to read past end of response file"); while (!_script->eos()) { - _script->readLine(_currentLine, 79); - // Commented out line, so go loop for another - if (_currentLine[0] == '#') + if (_currentLine[0] == '#') { + _script->readLine_OLD(_currentLine, 79); continue; + } // Process the line char *cStart = strchr(_currentLine, '['); @@ -284,6 +285,8 @@ void TextviewView::processLines() { processText(); break; } + + _script->readLine_OLD(_currentLine, 79); } } @@ -594,6 +597,7 @@ void AnimviewView::scriptDone() { } void AnimviewView::processLines() { + _script->readLine_OLD(_currentLine, 79); if (_script->eos()) { // end of script, end animation scriptDone(); @@ -601,8 +605,6 @@ void AnimviewView::processLines() { } while (!_script->eos()) { - _script->readLine(_currentLine, 79); - // Process the line char *cStart = strchr(_currentLine, '-'); if (cStart) { @@ -635,6 +637,8 @@ void AnimviewView::processLines() { //printf("File: %s\n", _currentLine); break; } + + _script->readLine_OLD(_currentLine, 79); } } diff --git a/engines/m4/midi.cpp b/engines/m4/midi.cpp index 51dd8654ae..3f1da2a369 100644 --- a/engines/m4/midi.cpp +++ b/engines/m4/midi.cpp @@ -269,7 +269,7 @@ byte *MidiPlayer::convertHMPtoSMF(byte *data, uint32 inSize, uint32 &outSize) { byte lastCmd = 0; // Now we can finally convert the track - uint32 endPos = readS.pos() + trackLength; + int32 endPos = readS.pos() + trackLength; while (readS.pos() < endPos) { // Convert the VLQ byte vlq[4]; diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp index 5070a2b79c..265e4dae0b 100644 --- a/engines/m4/resource.cpp +++ b/engines/m4/resource.cpp @@ -76,11 +76,11 @@ FileSystem::FileSystem(const char *hashFilename) { } /* load hagfile records and update the list */ - while (!hashFile.eof()) { + while (!hashFile.eos()) { HashHagEntry entry; hashFile.read(entry.filename, kM4MaxFilenameSize); entry.fileIndex = hashFile.readByte(); - if (hashFile.eof()) + if (hashFile.eos()) break; changeExtension(_hagEntries[entry.fileIndex].filename, entry.filename, "HAG"); diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index e5870bfeec..354e5bbb86 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -350,7 +350,7 @@ public: virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; + const Common::ADGameDescription *fallbackDetect(const Common::FSList *fslist) const; }; @@ -362,7 +362,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common return gd != 0; } -const Common::ADGameDescription *MadeMetaEngine::fallbackDetect(const FSList *fslist) const { +const Common::ADGameDescription *MadeMetaEngine::fallbackDetect(const Common::FSList *fslist) const { // Set the default values for the fallback descriptor's ADGameDescription part. Made::g_fallbackDesc.desc.language = Common::UNK_LANG; Made::g_fallbackDesc.desc.platform = Common::kPlatformPC; diff --git a/engines/made/music.cpp b/engines/made/music.cpp index c3b36d3b8c..0b58a11774 100644 --- a/engines/made/music.cpp +++ b/engines/made/music.cpp @@ -63,6 +63,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp index 831f1fab8e..6fe0f1c80d 100644 --- a/engines/made/pmvplayer.cpp +++ b/engines/made/pmvplayer.cpp @@ -95,13 +95,13 @@ void PmvPlayer::play(const char *filename) { // get it to work well? _audioStream = Audio::makeAppendableAudioStream(soundFreq, Audio::Mixer::FLAG_UNSIGNED); - while (!_abort && !_fd->eof()) { + while (!_abort && !_fd->eos()) { int32 frameTime = _vm->_system->getMillis(); readChunk(chunkType, chunkSize); - if (_fd->eof()) + if (_fd->eos()) break; frameData = new byte[chunkSize]; diff --git a/engines/made/redreader.cpp b/engines/made/redreader.cpp index 287574c312..a61d122041 100644 --- a/engines/made/redreader.cpp +++ b/engines/made/redreader.cpp @@ -55,9 +55,11 @@ Common::MemoryReadStream *RedReader::loadFromRed(const char *redFilename, const bool RedReader::seekFile(Common::File &fd, FileEntry &fileEntry, const char *filename) { char arcFilename[13]; - while (!fd.eof()) { + while (true) { fd.skip(8); // skip unknown fileEntry.compSize = fd.readUint32LE(); + if (fd.eos()) break; + fileEntry.origSize = fd.readUint32LE(); fd.skip(10); // skip unknown fd.read(arcFilename, 13); diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp index ee96af601a..6e9cf5c01a 100644 --- a/engines/made/screenfx.cpp +++ b/engines/made/screenfx.cpp @@ -132,7 +132,7 @@ void ScreenEffects::setBlendedPalette(byte *palette, byte *newPalette, int color if (!_screen->isPaletteLocked()) { int32 mulValue = (value * 64) / maxValue; for (int i = 0; i < colorCount * 3; i++) - _fxPalette[i] = CLIP(newPalette[i] - (newPalette[i] - palette[i]) * mulValue / 64, 0, 255); + _fxPalette[i] = CLIP<int32>(newPalette[i] - (newPalette[i] - palette[i]) * mulValue / 64, 0, 255); _screen->setRGBPalette(_fxPalette, 0, 256); } } diff --git a/engines/metaengine.h b/engines/metaengine.h index aef860e0f9..3a9f930eec 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -28,14 +28,17 @@ #include "common/scummsys.h" #include "common/str.h" #include "common/error.h" -#include "common/fs.h" -#include "base/game.h" +#include "engines/game.h" #include "base/plugins.h" class Engine; class OSystem; +namespace Common { + class FSList; +} + /** * A meta engine is essentially a factory for Engine instances with the * added ability of listing and detecting supported games. @@ -62,7 +65,7 @@ public: * (possibly empty) list of games supported by the engine which it was able * to detect amongst the given files. */ - virtual GameList detectGames(const FSList &fslist) const = 0; + virtual GameList detectGames(const Common::FSList &fslist) const = 0; /** * Tries to instantiate an engine instance based on the settings of @@ -79,9 +82,9 @@ public: /** * Return a list of all save states associated with the given target. * - * In general, the caller will already have ensured that this (Meta)Engine - * is responsible for the specified target by using findGame on it resp. - * on the associated gameid from the relevant ConfMan entry, if present. + * The caller has to ensure that this (Meta)Engine is responsible + * for the specified target (by using findGame on it respectively + * on the associated gameid from the relevant ConfMan entry, if present). * * The default implementation returns an empty list. * @@ -91,6 +94,92 @@ public: virtual SaveStateList listSaves(const char *target) const { return SaveStateList(); } + + /** + * Remove the specified save state. + * + * For most engines this just amounts to calling _saveFileMan->removeSaveFile(). + * Engines which keep an index file will also update it accordingly. + * + * @param target name of a config manager target + * @param slot slot number of the save state to be removed + */ + virtual void removeSaveState(const char *target, int slot) const {}; + + /** + * Returns meta infos from the specified save state. + * + * Depending on the MetaEngineFeatures set this can include + * thumbnails, save date / time, play time. + * + * @param target name of a config manager target + * @param slot slot number of the save state + */ + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const { return SaveStateDescriptor(); } + + /** @name MetaEngineFeature flags */ + //@{ + + /** + * A feature in this context means an ability of the engine which can be + * either available or not. + */ + enum MetaEngineFeature { + /** 'Return to launcher' feature (i.e. EVENT_RTL is handled) */ + kSupportsRTL = 0, + + /** + * Listing Save States (i.e. implements the listSaves() method; + * used for --list-saves support) + */ + kSupportsListSaves = 1, + + /** Loading from the Launcher / command line (-x) */ + kSupportsDirectLoad = 2, + + /** + * Deleting Saves from the Launcher (i.e. implements the + * removeSaveState() method) + */ + kSupportsDeleteSave = 3, + + /** + * Features meta infos for savestates (i.e. implements the + * querySaveMetaInfos method properly) + */ + kSupportsMetaInfos = 4, + + /** + * Features a thumbnail in savegames (i.e. includes a thumbnail + * in savestates returned via querySaveMetaInfo). + * This flag may only be set when 'kSupportsMetaInfos' is set. + */ + kSupportsThumbnails = 5, + + /** + * Features 'save_date' and 'save_time' entries in the + * savestate returned by querySaveMetaInfo. Those values + * indicate the date/time the savegame was created. + * This flag may only be set when 'kSupportsMetaInfos' is set. + */ + kSupportsSaveDate = 6, + + /** + * Features 'play_time' entry in the savestate returned by + * querySaveMetaInfo. It indicates how long the user played + * the game till the save. + * This flag may only be set when 'kSupportsMetaInfos' is set. + */ + kSupportsSavePlayTime = 7 + }; + + /** + * Determine whether the engine supports the specified MetaEngine feature. + * Used by e.g. the launcher to determine whether to enable the "Load" button. + */ + virtual bool hasFeature(MetaEngineFeature f) const { return false; }; + + //@} }; @@ -107,7 +196,7 @@ private: public: GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const; - GameList detectGames(const FSList &fslist) const; + GameList detectGames(const Common::FSList &fslist) const; const EnginePlugin::List &getPlugins() const; }; diff --git a/engines/module.mk b/engines/module.mk index 6cfe9b36fa..8102046c5b 100644 --- a/engines/module.mk +++ b/engines/module.mk @@ -1,7 +1,9 @@ MODULE := engines MODULE_OBJS := \ - engine.o + dialogs.o \ + engine.o \ + game.o # Include common rules include $(srcdir)/rules.mk diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp index 222954ec3a..290aa5e625 100644 --- a/engines/parallaction/balloons.cpp +++ b/engines/parallaction/balloons.cpp @@ -246,6 +246,8 @@ class BalloonManager_ns : public BalloonManager { static int16 _dialogueBalloonX[5]; + byte _textColors[2]; + struct Balloon { Common::Rect outerBox; Common::Rect innerBox; @@ -266,16 +268,18 @@ public: void freeBalloons(); int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); + int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); + void setBalloonText(uint id, char *text, TextColor textColor); int hitTestDialogueBalloon(int x, int y); }; int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 }; BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) { - + _textColors[kSelectedColor] = 0; + _textColors[kUnselectedColor] = 3; + _textColors[kNormalColor] = 0; } BalloonManager_ns::~BalloonManager_ns() { @@ -314,7 +318,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor winding = (winding == 0 ? 1 : 0); Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT); s.moveTo(r.width()/2 - 5, r.bottom - 1); - _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS); + _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_NS); } _numBalloons++; @@ -323,7 +327,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor } -int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) { int16 w, h; @@ -336,7 +340,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -347,7 +351,7 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w return id; } -int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) { int16 w, h; @@ -361,7 +365,7 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -377,12 +381,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC return id; } -void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) { +void BalloonManager_ns::setBalloonText(uint id, char *text, TextColor textColor) { Balloon *balloon = getBalloon(id); balloon->surface->fillRect(balloon->innerBox, 1); StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface); } @@ -398,7 +402,7 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) { int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS); Balloon *balloon = &_intBalloons[id]; StringWriter_NS sw(_vm->_dialogueFont); - sw.write(text, MAX_BALLOON_WIDTH, 0, balloon->surface); + sw.write(text, MAX_BALLOON_WIDTH, _textColors[kNormalColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -513,8 +517,6 @@ public: StringWriter_BR(Font *font) : WrappedLineFormatter(font) { } void write(const char *text, uint maxWidth, byte color, Graphics::Surface *surf) { - maxWidth = 216; - StringExtent_BR se(_font); se.calc(text, maxWidth); _width = se.width() + 10; @@ -534,6 +536,8 @@ public: class BalloonManager_br : public BalloonManager { + byte _textColors[2]; + struct Balloon { Common::Rect box; Graphics::Surface *surface; @@ -550,7 +554,7 @@ class BalloonManager_br : public BalloonManager { void cacheAnims(); void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth); - int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness); + int createBalloon(int16 w, int16 h, uint16 borderThickness); Balloon *getBalloon(uint id); Graphics::Surface *expandBalloon(Frames *data, int frameNum); @@ -562,9 +566,9 @@ public: void freeBalloons(); int setLocationBalloon(char *text, bool endGame); - int setDialogueBalloon(char *text, uint16 winding, byte textColor); - int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor); - void setBalloonText(uint id, char *text, byte textColor); + int setDialogueBalloon(char *text, uint16 winding, TextColor textColor); + int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor); + void setBalloonText(uint id, char *text, TextColor textColor); int hitTestDialogueBalloon(int x, int y); }; @@ -585,12 +589,12 @@ Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) Graphics::Surface *surf = new Graphics::Surface; surf->create(rect.width(), rect.height(), 1); - _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR); + _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_BR); return surf; } -int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) { +int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) { cacheAnims(); int id = _numBalloons; @@ -613,7 +617,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); - _writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + _writer.write(text, 216, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -626,7 +630,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w return id; } -int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) { +int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) { cacheAnims(); int id = _numBalloons; @@ -637,11 +641,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC if (winding == 0) { src = _rightBalloon; - srcFrame = id; + srcFrame = 0; } else if (winding == 1) { src = _leftBalloon; - srcFrame = 0; + srcFrame = id; } assert(src); @@ -649,7 +653,7 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC balloon->surface = expandBalloon(src, srcFrame); src->getRect(srcFrame, balloon->box); - _writer.write(text, MAX_BALLOON_WIDTH, textColor, balloon->surface); + _writer.write(text, 216, _textColors[textColor], balloon->surface); // TODO: extract some text to make a name for obj balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); @@ -657,32 +661,51 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC balloon->obj->y = balloon->box.top; balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR; - if (id > 0) { - balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height(); - } - _numBalloons++; return id; } -void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { } +void BalloonManager_br::setBalloonText(uint id, char *text, TextColor textColor) { + Balloon *balloon = getBalloon(id); + + StringWriter_BR sw(_vm->_dialogueFont); + sw.write(text, 216, _textColors[textColor], balloon->surface); +} + +int BalloonManager_br::createBalloon(int16 w, int16 h, uint16 borderThickness) { + assert(_numBalloons < 5); + + int id = _numBalloons; + Balloon *balloon = &_intBalloons[id]; + + balloon->surface = new Graphics::Surface; + balloon->surface->create(w, h, 1); + + Common::Rect rect(w, h); + balloon->surface->fillRect(rect, 1); + rect.grow(-borderThickness); + balloon->surface->fillRect(rect, 15); + + _numBalloons++; + + return id; +} int BalloonManager_br::setLocationBalloon(char *text, bool endGame) { -/* - int16 w, h; + StringExtent_BR se(_vm->_dialogueFont); - getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h); + se.calc(text, 240); - int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR); + int id = createBalloon(se.width() + 20, se.height() + 30, 2); Balloon *balloon = &_intBalloons[id]; - drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH); - // TODO: extract some text to make a name for obj + _writer.write(text, 240, kNormalColor, balloon->surface); + balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0); balloon->obj->x = 5; balloon->obj->y = 5; -*/ + return 0; } @@ -691,11 +714,9 @@ int BalloonManager_br::hitTestDialogueBalloon(int x, int y) { Common::Point p; for (uint i = 0; i < _numBalloons; i++) { - p.x = x - _intBalloons[i].obj->x; - p.y = y - _intBalloons[i].obj->y; - - if (_intBalloons[i].box.contains(p)) + if (_intBalloons[i].box.contains(x, y)) { return i; + } } return -1; @@ -723,6 +744,10 @@ void BalloonManager_br::cacheAnims() { BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0), _writer(_vm->_dialogueFont) { + + _textColors[kSelectedColor] = 12; + _textColors[kUnselectedColor] = 0; + _textColors[kNormalColor] = 0; } BalloonManager_br::~BalloonManager_br() { diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp index 0f89ca22d1..7915daa0b8 100644 --- a/engines/parallaction/callables_ns.cpp +++ b/engines/parallaction/callables_ns.cpp @@ -32,6 +32,7 @@ #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -170,7 +171,7 @@ void Parallaction_ns::_c_fade(void *parm) { _gfx->setPalette(pal); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } return; @@ -305,7 +306,7 @@ void Parallaction_ns::_c_endComment(void *param) { _gfx->setPalette(_gfx->_palette); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } _input->waitForButtonEvent(kMouseLeftUp); @@ -324,10 +325,10 @@ void Parallaction_ns::_c_frankenstein(void *parm) { } for (uint16 _di = 0; _di < 30; _di++) { - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal0); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal1); _gfx->updateScreen(); } @@ -341,7 +342,7 @@ void Parallaction_ns::_c_frankenstein(void *parm) { void Parallaction_ns::_c_finito(void *parm) { - setPartComplete(_char); + _saveLoad->setPartComplete(_char.getBaseName()); cleanInventory(); cleanupGame(); diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp index 0476b01454..d2444c642e 100644 --- a/engines/parallaction/detection.cpp +++ b/engines/parallaction/detection.cpp @@ -243,9 +243,20 @@ public: return "Nippon Safes Inc. (C) Dynabyte"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; }; +bool ParallactionMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Parallaction::PARALLACTIONGameDescription *gd = (const Parallaction::PARALLACTIONGameDescription *)desc; bool res = true; @@ -265,6 +276,43 @@ bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, cons return res; } +SaveStateList ParallactionMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + Common::String pattern = target; + pattern += ".0??"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 2 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 2); + + if (slotNum >= 0 && slotNum <= 99) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + Common::String saveDesc = in->readLine(); + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); + delete in; + } + } + } + + return saveList; +} + +void ParallactionMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".0%02d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + #if PLUGIN_ENABLED_DYNAMIC(PARALLACTION) REGISTER_PLUGIN_DYNAMIC(PARALLACTION, PLUGIN_TYPE_ENGINE, ParallactionMetaEngine); #else diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 205d702aa0..a2de3cbbf3 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -173,7 +173,7 @@ bool DialogueManager::displayAnswer(uint16 i) { // display suitable answers if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) { - int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3); + int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, BalloonManager::kUnselectedColor); assert(id >= 0); _visAnswers[id] = i; @@ -203,7 +203,7 @@ bool DialogueManager::displayAnswers() { if (_numVisAnswers == 1) { int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); _vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF); - _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0); + _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, BalloonManager::kNormalColor); } else if (_numVisAnswers > 1) { int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y); @@ -218,7 +218,7 @@ bool DialogueManager::displayAnswers() { bool DialogueManager::displayQuestion() { if (!scumm_stricmp(_q->_text, "NULL")) return false; - _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0); + _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, BalloonManager::kNormalColor); int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y); _vm->_gfx->setItemFrame(id, _q->_mood & 0xF); @@ -256,7 +256,7 @@ int16 DialogueManager::askPassword() { } if (_passwordChanged) { - _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3); + _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, BalloonManager::kNormalColor); _passwordChanged = false; } @@ -286,11 +286,11 @@ int16 DialogueManager::selectAnswerN() { if (_selection != _oldSelection) { if (_oldSelection != -1) { - _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3); + _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, BalloonManager::kUnselectedColor); } if (_selection != -1) { - _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0); + _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, BalloonManager::kSelectedColor); _vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF); } } diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 2923f239d4..30d820c6d2 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -29,10 +29,12 @@ #define PATH_LEN 200 #include "common/fs.h" - #include "common/file.h" + #include "graphics/surface.h" +#include "parallaction/graphics.h" + namespace Parallaction { class Table; @@ -102,10 +104,10 @@ public: Common::String name() const; bool openArchivedFile(const char *name); void closeArchivedFile(); - uint32 size() const; - uint32 pos() const; + int32 size() const; + int32 pos() const; bool eos() const; - void seek(int32 offs, int whence = SEEK_SET); + bool seek(int32 offs, int whence = SEEK_SET); uint32 read(void *dataPtr, uint32 dataSize); }; @@ -209,21 +211,21 @@ protected: Parallaction *_vm; - FilesystemNode _baseDir; - FilesystemNode _partDir; + Common::FilesystemNode _baseDir; + Common::FilesystemNode _partDir; - FilesystemNode _aniDir; - FilesystemNode _bkgDir; - FilesystemNode _mscDir; - FilesystemNode _mskDir; - FilesystemNode _pthDir; - FilesystemNode _rasDir; - FilesystemNode _scrDir; - FilesystemNode _sfxDir; - FilesystemNode _talDir; + Common::FilesystemNode _aniDir; + Common::FilesystemNode _bkgDir; + Common::FilesystemNode _mscDir; + Common::FilesystemNode _mskDir; + Common::FilesystemNode _pthDir; + Common::FilesystemNode _rasDir; + Common::FilesystemNode _scrDir; + Common::FilesystemNode _sfxDir; + Common::FilesystemNode _talDir; protected: - void errorFileNotFound(const FilesystemNode &dir, const Common::String &filename); + void errorFileNotFound(const Common::FilesystemNode &dir, const Common::String &filename); Font *createFont(const char *name, Common::ReadStream &stream); Sprites* createSprites(Common::ReadStream &stream); void loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette); @@ -271,14 +273,14 @@ protected: Font *createFont(const char *name, Common::SeekableReadStream &stream); void loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream); - FilesystemNode _baseBkgDir; - FilesystemNode _fntDir; - FilesystemNode _commonAniDir; - FilesystemNode _commonBkgDir; - FilesystemNode _commonMscDir; - FilesystemNode _commonMskDir; - FilesystemNode _commonPthDir; - FilesystemNode _commonTalDir; + Common::FilesystemNode _baseBkgDir; + Common::FilesystemNode _fntDir; + Common::FilesystemNode _commonAniDir; + Common::FilesystemNode _commonBkgDir; + Common::FilesystemNode _commonMscDir; + Common::FilesystemNode _commonMskDir; + Common::FilesystemNode _commonPthDir; + Common::FilesystemNode _commonTalDir; public: AmigaDisk_br(Parallaction *vm); diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index f52567bea2..24893b7b05 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -91,7 +91,7 @@ struct Sprites : public Frames { -void DosDisk_br::errorFileNotFound(const FilesystemNode &dir, const Common::String &filename) { +void DosDisk_br::errorFileNotFound(const Common::FilesystemNode &dir, const Common::String &filename) { error("File '%s' not found in directory '%s'", filename.c_str(), dir.getDisplayName().c_str()); } @@ -134,7 +134,7 @@ GfxObj* DosDisk_br::loadTalk(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name); Common::String path(name); - FilesystemNode node = _talDir.getChild(path); + Common::FilesystemNode node = _talDir.getChild(path); if (!node.exists()) { path += ".tal"; node = _talDir.getChild(path); @@ -160,11 +160,11 @@ Script* DosDisk_br::loadLocation(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadLocation"); Common::String langs[4] = { "it", "fr", "en", "ge" }; - FilesystemNode locDir = _partDir.getChild(langs[_language]); + Common::FilesystemNode locDir = _partDir.getChild(langs[_language]); Common::String path(name); path += ".slf"; - FilesystemNode node = locDir.getChild(path); + Common::FilesystemNode node = locDir.getChild(path); if (!node.exists()) { path = Common::String(name) + ".loc"; node = locDir.getChild(path); @@ -183,7 +183,7 @@ Script* DosDisk_br::loadScript(const char* name) { Common::String path(name); path += ".scr"; - FilesystemNode node = _scrDir.getChild(path); + Common::FilesystemNode node = _scrDir.getChild(path); if (!node.exists()) { errorFileNotFound(_scrDir, path); } @@ -221,7 +221,7 @@ Frames* DosDisk_br::loadPointer(const char *name) { Common::String path(name); path += ".ras"; - FilesystemNode node = _baseDir.getChild(path); + Common::FilesystemNode node = _baseDir.getChild(path); if (!node.exists()) { errorFileNotFound(_baseDir, path); } @@ -240,7 +240,7 @@ Font* DosDisk_br::loadFont(const char* name) { Common::String path(name); path += ".fnt"; - FilesystemNode node = _baseDir.getChild(path); + Common::FilesystemNode node = _baseDir.getChild(path); if (!node.exists()) { errorFileNotFound(_baseDir, path); } @@ -255,7 +255,7 @@ GfxObj* DosDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "DosDisk_br::loadObjects"); Common::String path(name); - FilesystemNode node = _partDir.getChild(path); + Common::FilesystemNode node = _partDir.getChild(path); if (!node.exists()) { errorFileNotFound(_partDir, path); } @@ -274,7 +274,7 @@ GfxObj* DosDisk_br::loadStatic(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadStatic"); Common::String path(name); - FilesystemNode node = _rasDir.getChild(path); + Common::FilesystemNode node = _rasDir.getChild(path); if (!node.exists()) { errorFileNotFound(_rasDir, path); } @@ -312,7 +312,7 @@ Frames* DosDisk_br::loadFrames(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadFrames"); Common::String path(name); - FilesystemNode node = _aniDir.getChild(path); + Common::FilesystemNode node = _aniDir.getChild(path); if (!node.exists()) { path += ".ani"; node = _aniDir.getChild(path); @@ -336,7 +336,7 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) { Common::String path(name); path += ".bmp"; - FilesystemNode node = _baseDir.getChild(path); + Common::FilesystemNode node = _baseDir.getChild(path); if (!node.exists()) { errorFileNotFound(_baseDir, path); } @@ -363,7 +363,7 @@ void DosDisk_br::loadMask(const char *name, MaskBuffer &buffer) { } Common::String filepath; - FilesystemNode node; + Common::FilesystemNode node; Common::File stream; filepath = Common::String(name) + ".msk"; @@ -384,7 +384,7 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char debugC(5, kDebugDisk, "DosDisk_br::loadScenery"); Common::String filepath; - FilesystemNode node; + Common::FilesystemNode node; Common::File stream; if (name) { @@ -447,7 +447,7 @@ Table* DosDisk_br::loadTable(const char* name) { Common::String path(name); path += ".tab"; - FilesystemNode node = _partDir.getChild(path); + Common::FilesystemNode node = _partDir.getChild(path); if (!node.exists()) { errorFileNotFound(_partDir, path); } @@ -518,7 +518,7 @@ AmigaDisk_br::AmigaDisk_br(Parallaction *vm) : DosDisk_br(vm) { _baseBkgDir = _baseDir.getChild("backs"); - FilesystemNode commonDir = _baseDir.getChild("common"); + Common::FilesystemNode commonDir = _baseDir.getChild("common"); _commonAniDir = commonDir.getChild("anims"); _commonBkgDir = commonDir.getChild("backs"); _commonMscDir = commonDir.getChild("msc"); @@ -566,7 +566,7 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery '%s', '%s' '%s'", name, mask, path); Common::String filepath; - FilesystemNode node; + Common::FilesystemNode node; Common::File stream; if (name) { @@ -630,7 +630,7 @@ void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) { Common::String path(name); path += ".bkg"; - FilesystemNode node = _baseBkgDir.getChild(path); + Common::FilesystemNode node = _baseBkgDir.getChild(path); if (!node.exists()) { errorFileNotFound(_baseBkgDir, path); } @@ -644,7 +644,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name); Common::String path(name); - FilesystemNode node = _rasDir.getChild(path); + Common::FilesystemNode node = _rasDir.getChild(path); if (!node.exists()) { errorFileNotFound(_rasDir, path); } @@ -687,7 +687,7 @@ Frames* AmigaDisk_br::loadFrames(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name); Common::String path(name); - FilesystemNode node = _aniDir.getChild(path); + Common::FilesystemNode node = _aniDir.getChild(path); if (!node.exists()) { path += ".ani"; node = _aniDir.getChild(path); @@ -713,7 +713,7 @@ GfxObj* AmigaDisk_br::loadTalk(const char *name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name); Common::String path(name); - FilesystemNode node = _talDir.getChild(path); + Common::FilesystemNode node = _talDir.getChild(path); if (!node.exists()) { path += ".tal"; node = _talDir.getChild(path); @@ -740,7 +740,7 @@ Font* AmigaDisk_br::loadFont(const char* name) { Common::String path(name); path += ".font"; - FilesystemNode node = _fntDir.getChild(path); + Common::FilesystemNode node = _fntDir.getChild(path); if (!node.exists()) { errorFileNotFound(_fntDir, path); } @@ -773,7 +773,7 @@ Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) { debugC(5, kDebugDisk, "AmigaDisk_br::loadMusic"); Common::String path(name); - FilesystemNode node = _mscDir.getChild(path); + Common::FilesystemNode node = _mscDir.getChild(path); if (!node.exists()) { // TODO (Kirben): error out when music file is not found? return 0; @@ -789,7 +789,7 @@ Common::ReadStream* AmigaDisk_br::loadSound(const char* name) { debugC(5, kDebugDisk, "AmigaDisk_br::loadSound"); Common::String path(name); - FilesystemNode node = _sfxDir.getChild(path); + Common::FilesystemNode node = _sfxDir.getChild(path); if (!node.exists()) { errorFileNotFound(_sfxDir, path); } @@ -803,7 +803,7 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name) { debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects"); Common::String path(name); - FilesystemNode node = _partDir.getChild(path); + Common::FilesystemNode node = _partDir.getChild(path); if (!node.exists()) { errorFileNotFound(_partDir, path); } diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 55e6fc5e77..54d4d1e5da 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -156,19 +156,19 @@ void Archive::closeArchivedFile() { } -uint32 Archive::size() const { +int32 Archive::size() const { return (_file == true ? _fileEndOffset - _fileOffset : 0); } -uint32 Archive::pos() const { +int32 Archive::pos() const { return (_file == true ? _fileCursor - _fileOffset : 0 ); } bool Archive::eos() const { - return (_file == true ? _fileCursor == _fileEndOffset : true ); + return (_file == true ? _fileCursor == _fileEndOffset : true ); // FIXME (eos definition change) } -void Archive::seek(int32 offs, int whence) { +bool Archive::seek(int32 offs, int whence) { assert(_file == true && _fileCursor <= _fileEndOffset); switch (whence) { @@ -184,7 +184,7 @@ void Archive::seek(int32 offs, int whence) { } assert(_fileCursor <= _fileEndOffset && _fileCursor >= _fileOffset); - _archive.seek(_fileCursor, SEEK_SET); + return _archive.seek(_fileCursor, SEEK_SET); } uint32 Archive::read(void *dataPtr, uint32 dataSize) { @@ -234,16 +234,16 @@ public: return _input->read(data, dataSize); } - uint32 pos() const { + int32 pos() const { return _input->pos(); } - uint32 size() const { + int32 size() const { return _input->size(); } - void seek(int32 offset, int whence) { - _input->seek(offset, whence); + bool seek(int32 offset, int whence) { + return _input->seek(offset, whence); } }; @@ -798,11 +798,11 @@ public: if (_dispose) delete _stream; } - uint32 size() const { + int32 size() const { return _stream->size(); } - uint32 pos() const { + int32 pos() const { return _stream->pos(); } @@ -810,8 +810,8 @@ public: return _stream->eos(); } - void seek(int32 offs, int whence = SEEK_SET) { - _stream->seek(offs, whence); + bool seek(int32 offs, int whence = SEEK_SET) { + return _stream->seek(offs, whence); } uint32 read(void *dataPtr, uint32 dataSize) { diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index fe7b1b2903..bcc4a5b532 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -546,27 +546,4 @@ ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm ProgramExec_br::~ProgramExec_br() { } -#if 0 -void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) { - -} - -void Parallaction_br::jobPauseSfx(void *parm, Job *job) { - -} - - -void Parallaction_br::jobStopFollower(void *parm, Job *job) { - -} - - -void Parallaction_br::jobScroll(void *parm, Job *job) { - -} -#endif - - - - } // namespace Parallaction diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp index 4ea7d601e0..2ce50f498e 100644 --- a/engines/parallaction/exec_ns.cpp +++ b/engines/parallaction/exec_ns.cpp @@ -247,32 +247,6 @@ DECLARE_COMMAND_OPCODE(close) { _vm->updateDoor(_ctxt.cmd->u._zone, true); } -void Parallaction::showZone(ZonePtr z, bool visible) { - if (!z) { - return; - } - - if (visible) { - z->_flags &= ~kFlagsRemove; - z->_flags |= kFlagsActive; - } else { - z->_flags |= kFlagsRemove; - } - - if ((z->_type & 0xFFFF) == kZoneGet) { - _gfx->showGfxObj(z->u.get->gfxobj, visible); - - GetData *data = z->u.get; - if (data->hasMask && _gfx->_backgroundInfo->hasMask) { - if (visible) { - _gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); - } else { - _gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); - } - } - } -} - DECLARE_COMMAND_OPCODE(on) { _vm->showZone(_ctxt.cmd->u._zone, true); } @@ -304,7 +278,8 @@ DECLARE_COMMAND_OPCODE(drop){ DECLARE_COMMAND_OPCODE(quit) { - _engineFlags |= kEngineQuit; + _vm->_quit = true; + _vm->quitGame(); } @@ -318,66 +293,6 @@ DECLARE_COMMAND_OPCODE(stop) { } -void Parallaction_ns::drawAnimations() { - debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); - - uint16 layer = 0; - - for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { - - AnimationPtr anim = *it; - GfxObj *obj = anim->gfxobj; - - // Validation is performed here, so that every animation is affected, instead that only the ones - // who *own* a script. In fact, some scripts can change values in other animations. - // The right way to do this would be to enforce validation when any variable is modified from - // a script. - anim->validateScriptVars(); - - if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { - - if (anim->_flags & kFlagsNoMasked) - layer = LAYER_FOREGROUND; - else { - if (getGameType() == GType_Nippon) { - // Layer in NS depends on where the animation is on the screen, for each animation. - layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); - } else { - // Layer in BRA is calculated from Z value. For characters it is the same as NS, - // but other animations can have Z set from scripts independently from their - // position on the screen. - layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); - } - } - - if (obj) { - _gfx->showGfxObj(obj, true); - obj->frame = anim->getF(); - obj->x = anim->getX(); - obj->y = anim->getY(); - obj->z = anim->getZ(); - obj->layer = layer; - } - } - - if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) { - anim->_flags &= ~kFlagsRemove; - } - - if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) { - anim->_flags &= ~kFlagsActive; - anim->_flags |= kFlagsRemove; - if (obj) { - _gfx->showGfxObj(obj, false); - } - } - } - - debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); - - return; -} - void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) { debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name); @@ -442,7 +357,7 @@ void CommandExec::runList(CommandList::iterator first, CommandList::iterator las _ctxt.suspend = false; for ( ; first != last; first++) { - if (_engineFlags & kEngineQuit) + if (_vm->quit()) break; CommandPtr cmd = *first; @@ -532,239 +447,6 @@ CommandExec_ns::~CommandExec_ns() { } -// -// ZONE TYPE: EXAMINE -// - -void Parallaction::enterCommentMode(ZonePtr z) { - if (!z) { - return; - } - - _commentZone = z; - - ExamineData *data = _commentZone->u.examine; - - if (!data->_description) { - return; - } - - // TODO: move this balloons stuff into DialogueManager and BalloonManager - if (getGameType() == GType_Nippon) { - int id; - if (data->_filename) { - if (data->_cnv == 0) { - data->_cnv = _disk->loadStatic(data->_filename); - } - - _gfx->setHalfbriteMode(true); - _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0); - Common::Rect r; - data->_cnv->getRect(0, r); - id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); - _gfx->setItemFrame(id, 0); - id = _gfx->setItem(_char._head, 100, 152); - _gfx->setItemFrame(id, 0); - } else { - _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0); - id = _gfx->setItem(_char._talk, 190, 80); - _gfx->setItemFrame(id, 0); - } - } else - if (getGameType() == GType_BRA) { - _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0); - int id = _gfx->setItem(_char._talk, 10, 80); - _gfx->setItemFrame(id, 0); - } - - _input->_inputMode = Input::kInputModeComment; -} - -void Parallaction::exitCommentMode() { - _input->_inputMode = Input::kInputModeGame; - - hideDialogueStuff(); - _gfx->setHalfbriteMode(false); - - _cmdExec->run(_commentZone->_commands, _commentZone); - _commentZone = nullZonePtr; -} - -void Parallaction::runCommentFrame() { - if (_input->_inputMode != Input::kInputModeComment) { - return; - } - - if (_input->getLastButtonEvent() == kMouseLeftUp) { - exitCommentMode(); - } -} - - -void Parallaction::runZone(ZonePtr z) { - debugC(3, kDebugExec, "runZone (%s)", z->_name); - - uint16 subtype = z->_type & 0xFFFF; - - debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); - switch(subtype) { - - case kZoneExamine: - enterCommentMode(z); - return; - - case kZoneGet: - pickupItem(z); - break; - - case kZoneDoor: - if (z->_flags & kFlagsLocked) break; - updateDoor(z, !(z->_flags & kFlagsClosed)); - break; - - case kZoneHear: - _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); - break; - - case kZoneSpeak: - enterDialogueMode(z); - return; - } - - debugC(3, kDebugExec, "runZone completed"); - - _cmdExec->run(z->_commands, z); - - return; -} - -// -// ZONE TYPE: DOOR -// -void Parallaction::updateDoor(ZonePtr z, bool close) { - z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); - - if (z->u.door->gfxobj) { - uint frame = (close ? 0 : 1); -// z->u.door->gfxobj->setFrame(frame); - z->u.door->gfxobj->frame = frame; - } - - return; -} - - - -// -// ZONE TYPE: GET -// - -bool Parallaction::pickupItem(ZonePtr z) { - if (z->_flags & kFlagsFixed) { - return false; - } - - int slot = addInventoryItem(z->u.get->_icon); - if (slot != -1) { - showZone(z, false); - } - - return (slot != -1); -} - - - -ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { -// printf("hitZone(%i, %i, %i)", type, x, y); - - uint16 _di = y; - uint16 _si = x; - - for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { -// printf("Zone name: %s", z->_name); - - ZonePtr z = *it; - - if (z->_flags & kFlagsRemove) continue; - - Common::Rect r; - z->getBox(r); - r.right++; // adjust border because Common::Rect doesn't include bottom-right edge - r.bottom++; - - r.grow(-1); // allows some tolerance for mouse click - - if (!r.contains(_si, _di)) { - - // out of Zone, so look for special values - if ((z->getX() == -2) || (z->getX() == -3)) { - - // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs - // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, - // but we need to check it separately here. The same workaround is applied in freeZones. - if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) || - (((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) { - - // special Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - } - - if (z->getX() != -1) - continue; - if (_si < _char._ani->getFrameX()) - continue; - if (_si > (_char._ani->getFrameX() + _char._ani->width())) - continue; - if (_di < _char._ani->getFrameY()) - continue; - if (_di > (_char._ani->getFrameY() + _char._ani->height())) - continue; - - } - - // normal Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - - - int16 _a, _b, _c, _d, _e, _f; - for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { - - AnimationPtr a = *ait; - - _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation - _e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1; // _e: horizontal range - _f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1; // _f: vertical range - - _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) - _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object - _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type - - if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { - - return a; - - } - - } - - return nullZonePtr; -} - - void CommandExec_ns::init() { Common::Array<const Opcode*> *table = 0; diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 1c373dda44..8eb9753edd 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -32,7 +32,7 @@ namespace Parallaction { -GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3) { +GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3), scale(100) { if (name) { _name = strdup(name); } else { @@ -180,9 +180,9 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) { data = obj->getData(obj->frame); if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { - blt(rect, data, &surf, obj->layer, obj->transparentKey); + blt(rect, data, &surf, obj->layer, obj->scale, obj->transparentKey); } else { - unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey); + unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->scale, obj->transparentKey); } } @@ -233,7 +233,7 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf blt(r, _unpackedBitmap, surf, z, transparentColor); } #endif -void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { byte *d = _unpackedBitmap; uint pixelsLeftInLine = r.width(); @@ -259,11 +259,154 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf d += repeat; } - blt(r, _unpackedBitmap, surf, z, transparentColor); + blt(r, _unpackedBitmap, surf, z, scale, transparentColor); } -void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { +void Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { + if (scale == 100) { + // use optimized path + bltMaskNoScale(r, data, surf, z, transparentColor); + return; + } + + Common::Rect q(r); + Common::Rect clipper(surf->w, surf->h); + q.clip(clipper); + if (!q.isValidRect()) return; + + uint inc = r.width() * (100 - scale); + uint thr = r.width() * 100; + uint xAccum = 0, yAccum = 0; + + Common::Point dp; + dp.x = q.left + (r.width() * (100 - scale)) / 200; + dp.y = q.top + (r.height() * (100 - scale)) / 100; + q.translate(-r.left, -r.top); + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint line = 0, col = 0; + + for (uint16 i = 0; i < q.height(); i++) { + yAccum += inc; + + if (yAccum >= thr) { + yAccum -= thr; + s += r.width(); + continue; + } + + xAccum = 0; + byte *d2 = d; + col = 0; + + for (uint16 j = 0; j < q.width(); j++) { + xAccum += inc; + + if (xAccum >= thr) { + xAccum -= thr; + s++; + continue; + } + + if (*s != transparentColor) { + byte v = _backgroundInfo->mask.getValue(dp.x + col, dp.y + line); + if (z >= v) *d2 = *s; + } + + s++; + d2++; + col++; + } + + s += r.width() - q.width(); + d += surf->w; + line++; + } + +} + +void Gfx::bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) { + if (!_backgroundInfo->mask.data || (z == LAYER_FOREGROUND)) { + // use optimized path + bltNoMaskNoScale(r, data, surf, transparentColor); + return; + } + + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + for (uint16 i = 0; i < q.height(); i++) { + + for (uint16 j = 0; j < q.width(); j++) { + if (*s != transparentColor) { + byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); + if (z >= v) *d = *s; + } + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } + +} + +void Gfx::bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor) { + Common::Point dp; + Common::Rect q(r); + + Common::Rect clipper(surf->w, surf->h); + + q.clip(clipper); + if (!q.isValidRect()) return; + + dp.x = q.left; + dp.y = q.top; + + q.translate(-r.left, -r.top); + + byte *s = data + q.left + q.top * r.width(); + byte *d = (byte*)surf->getBasePtr(dp.x, dp.y); + + uint sPitch = r.width() - q.width(); + uint dPitch = surf->w - q.width(); + + for (uint16 i = q.top; i < q.bottom; i++) { + for (uint16 j = q.left; j < q.right; j++) { + if (*s != transparentColor) + *d = *s; + + s++; + d++; + } + + s += sPitch; + d += dPitch; + } +} + + +void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) { Common::Point dp; Common::Rect q(r); @@ -308,40 +451,7 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 } } else { - if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) { - - for (uint16 i = 0; i < q.height(); i++) { - - for (uint16 j = 0; j < q.width(); j++) { - if (*s != transparentColor) { - byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i); - if (z >= v) *d = *s; - } - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } else { - - for (uint16 i = q.top; i < q.bottom; i++) { - for (uint16 j = q.left; j < q.right; j++) { - if (*s != transparentColor) - *d = *s; - - s++; - d++; - } - - s += sPitch; - d += dPitch; - } - - } + bltMaskScale(r, data, surf, z, scale, transparentColor); } } diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 1c2cb58b5b..2bd3935f01 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -34,8 +34,9 @@ namespace Parallaction { // this is the size of the receiving buffer for unpacked frames, -// since BRA uses some insanely big animations. -#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401 +// since BRA uses some insanely big animations (the largest is +// part0/ani/dino.ani). +#define MAXIMUM_UNPACKED_BITMAP_SIZE 641*401 void Gfx::registerVar(const Common::String &name, int32 initialValue) { @@ -251,7 +252,7 @@ void Gfx::setPalette(Palette pal) { byte sysPal[256*4]; uint n = pal.fillRGBA(sysPal); - g_system->setPalette(sysPal, 0, n); + _vm->_system->setPalette(sysPal, 0, n); } void Gfx::setBlackPalette() { @@ -327,7 +328,7 @@ void Gfx::drawInventory() { _vm->_inventoryRenderer->getRect(r); byte *data = _vm->_inventoryRenderer->getData(); - g_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); + _vm->_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); } void Gfx::drawItems() { @@ -335,11 +336,11 @@ void Gfx::drawItems() { return; } - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); for (uint i = 0; i < _numItems; i++) { drawGfxObject(_items[i].data, *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } void Gfx::drawBalloons() { @@ -347,15 +348,15 @@ void Gfx::drawBalloons() { return; } - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); for (uint i = 0; i < _balloons.size(); i++) { drawGfxObject(_balloons[i], *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } void Gfx::clearScreen() { - g_system->clearScreen(); + _vm->_system->clearScreen(); } void Gfx::beginFrame() { @@ -377,7 +378,7 @@ void Gfx::beginFrame() { *data++ = _backgroundInfo->mask.getValue(x, y); } } -#if 1 +#if 0 Common::DumpFile dump; dump.open("maskdump.bin"); dump.write(_bitmapMask.pixels, _bitmapMask.w * _bitmapMask.h); @@ -437,11 +438,11 @@ void Gfx::updateScreen() { backgroundPitch = _bitmapMask.pitch; break; } - g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); + _vm->_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); } if (_varDrawPathZones == 1) { - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); ZoneList::iterator b = _vm->_location._zones.begin(); ZoneList::iterator e = _vm->_location._zones.end(); for (; b != e; b++) { @@ -450,13 +451,13 @@ void Gfx::updateScreen() { surf->frameRect(Common::Rect(z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height()), 2); } } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } _varRenderMode = _varAnimRenderMode; // TODO: transform objects coordinates to be drawn with scrolling - Graphics::Surface *surf = g_system->lockScreen(); + Graphics::Surface *surf = _vm->_system->lockScreen(); drawGfxObjects(*surf); if (_halfbrite) { @@ -480,7 +481,7 @@ void Gfx::updateScreen() { } } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); _varRenderMode = _varMiscRenderMode; @@ -489,7 +490,7 @@ void Gfx::updateScreen() { drawBalloons(); drawLabels(); - g_system->updateScreen(); + _vm->_system->updateScreen(); return; } @@ -506,7 +507,7 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask) r.moveTo(x, y); uint16 z = (mask) ? _backgroundInfo->getLayer(y) : LAYER_FOREGROUND; - blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 0); + blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 100, 0); } void Gfx::fillBackground(const Common::Rect& r, byte color) { @@ -600,30 +601,41 @@ void Gfx::updateFloatingLabel() { return; } - int16 _si, _di; - - Common::Point cursor; - _vm->_input->getCursorPos(cursor); + struct FloatingLabelTraits { + Common::Point _offsetWithItem; + Common::Point _offsetWithoutItem; + int _minX; + int _minY; + int _maxX; + int _maxY; + } *traits; Common::Rect r; _labels[_floatingLabel]->getRect(0, r); - if (_vm->_input->_activeItem._id != 0) { - _si = cursor.x + 16 - r.width()/2; - _di = cursor.y + 34; + if (_vm->getGameType() == GType_Nippon) { + FloatingLabelTraits traits_NS = { + Common::Point(16 - r.width()/2, 34), + Common::Point(8 - r.width()/2, 21), + 0, 0, _vm->_screenWidth - r.width(), 190 + }; + traits = &traits_NS; } else { - _si = cursor.x + 8 - r.width()/2; - _di = cursor.y + 21; + // FIXME: _maxY for BRA is not constant (390), but depends on _vm->_subtitleY + FloatingLabelTraits traits_BR = { + Common::Point(34 - r.width()/2, 70), + Common::Point(16 - r.width()/2, 37), + 0, 0, _vm->_screenWidth - r.width(), 390 + }; + traits = &traits_BR; } - if (_si < 0) _si = 0; - if (_di > 190) _di = 190; - - if (r.width() + _si > _vm->_screenWidth) - _si = _vm->_screenWidth - r.width(); + Common::Point cursor; + _vm->_input->getCursorPos(cursor); + Common::Point offset = (_vm->_input->_activeItem._id) ? traits->_offsetWithItem : traits->_offsetWithoutItem; - _labels[_floatingLabel]->x = _si; - _labels[_floatingLabel]->y = _di; + _labels[_floatingLabel]->x = CLIP(cursor.x + offset.x, traits->_minX, traits->_maxX); + _labels[_floatingLabel]->y = CLIP(cursor.y + offset.y, traits->_minY, traits->_maxY); } @@ -703,13 +715,13 @@ void Gfx::drawLabels() { updateFloatingLabel(); - Graphics::Surface* surf = g_system->lockScreen(); + Graphics::Surface* surf = _vm->_system->lockScreen(); for (uint i = 0; i < _labels.size(); i++) { drawGfxObject(_labels[i], *surf, false); } - g_system->unlockScreen(); + _vm->_system->unlockScreen(); } @@ -737,10 +749,10 @@ void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) { Gfx::Gfx(Parallaction* vm) : _vm(vm), _disk(vm->_disk) { - g_system->beginGFXTransaction(); - g_system->initSize(_vm->_screenWidth, _vm->_screenHeight); + _vm->_system->beginGFXTransaction(); + _vm->_system->initSize(_vm->_screenWidth, _vm->_screenHeight); _vm->initCommonGFX(_vm->getGameType() == GType_BRA); - g_system->endGFXTransaction(); + _vm->_system->endGFXTransaction(); setPalette(_palette); diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 471f71dfa8..ac9f096d7e 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -313,6 +313,7 @@ struct Cnv : public Frames { uint16 _height; // byte** field_8; // unused byte* _data; + bool _freeData; public: Cnv() { @@ -320,12 +321,14 @@ public: _data = NULL; } - Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data) : _count(numFrames), _width(width), _height(height), _data(data) { + Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data, bool freeData = false) + : _count(numFrames), _width(width), _height(height), _data(data), _freeData(freeData) { } ~Cnv() { - free(_data); + if (_freeData) + free(_data); } byte* getFramePtr(uint16 index) { @@ -410,6 +413,7 @@ public: uint frame; uint layer; uint transparentKey; + uint scale; GfxObj(uint type, Frames *frames, const char *name = NULL); virtual ~GfxObj(); @@ -495,13 +499,19 @@ enum { class BalloonManager { public: + enum TextColor { + kSelectedColor = 0, + kUnselectedColor = 1, + kNormalColor = 2 + }; + virtual ~BalloonManager() { } virtual void freeBalloons() = 0; virtual int setLocationBalloon(char *text, bool endGame) = 0; - virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0; - virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0; - virtual void setBalloonText(uint id, char *text, byte textColor) = 0; + virtual int setDialogueBalloon(char *text, uint16 winding, TextColor textColor) = 0; + virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) = 0; + virtual void setBalloonText(uint id, char *text, TextColor textColor) = 0; virtual int hitTestDialogueBalloon(int x, int y) = 0; }; @@ -640,8 +650,12 @@ public: void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene); - void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); - void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor); + void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + + void bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor); + void bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor); + void bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor); }; diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp index 3315433762..c687a15026 100644 --- a/engines/parallaction/gui_br.cpp +++ b/engines/parallaction/gui_br.cpp @@ -28,6 +28,7 @@ #include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" namespace Parallaction { @@ -40,11 +41,11 @@ protected: Palette blackPal; Palette pal; - Parallaction_br *_vm; + Parallaction *_vm; int _fadeSteps; public: - SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { } virtual MenuInputState* run() { @@ -52,8 +53,6 @@ public: pal.fadeTo(blackPal, 1); _vm->_gfx->setPalette(pal); _fadeSteps--; - // TODO: properly implement timers to avoid delay calls - _vm->_system->delayMillis(20); return this; } @@ -75,7 +74,7 @@ public: _vm->showSlide(_slideName.c_str(), CENTER_LABEL_HORIZONTAL, CENTER_LABEL_VERTICAL); _vm->_input->setMouseState(MOUSE_DISABLED); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _fadeSteps = -1; } }; @@ -152,6 +151,8 @@ class MainMenuInputState_BR : public MenuInputState { static const char *_menuStrings[NUM_MENULINES]; static const MenuOptions _options[NUM_MENULINES]; + static const char *_firstLocation[]; + int _availItems; int _selection; @@ -166,16 +167,18 @@ class MainMenuInputState_BR : public MenuInputState { void performChoice(int selectedItem) { switch (selectedItem) { - case kMenuQuit: - _engineFlags |= kEngineQuit; + case kMenuQuit: { + _vm->_quit = true; + _vm->quitGame(); break; + } case kMenuLoadGame: warning("loadgame not yet implemented"); break; default: - _vm->startPart(selectedItem); + _vm->scheduleLocationSwitch(_firstLocation[selectedItem]); } } @@ -213,31 +216,40 @@ public: virtual void enter() { _vm->_gfx->clearScreen(); - int x = 0, y = 0; + int x = 0, y = 0, i = 0; if (_vm->getPlatform() == Common::kPlatformPC) { x = 20; y = 50; } _vm->showSlide("tbra", x, y); - // TODO: load progress from savefile - int progress = 3; - _availItems = 4 + progress; + _availItems = 4; + + bool complete[3]; + _vm->_saveLoad->getGamePartProgress(complete, 3); + for (i = 0; i < 3 && complete[i]; i++, _availItems++) ; // TODO: keep track of and destroy menu item frames/surfaces - int i; for (i = 0; i < _availItems; i++) { _lines[i] = new GfxObj(0, renderMenuItem(_menuStrings[i]), "MenuItem"); uint id = _vm->_gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF); _vm->_gfx->setItemFrame(id, 0); } _selection = -1; - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); } }; +const char *MainMenuInputState_BR::_firstLocation[] = { + "intro.0", + "museo.1", + "start.2", + "bolscoi.3", + "treno.4" +}; + const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = { "SEE INTRO", "NEW GAME", @@ -264,29 +276,24 @@ const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MEN -void Parallaction_br::startGui() { +void Parallaction_br::startGui(bool showSplash) { _menuHelper = new MenuInputHelper; - new SplashInputState0_BR(this, _menuHelper); - new SplashInputState1_BR(this, _menuHelper); - new MainMenuInputState_BR(this, _menuHelper); - _menuHelper->setState("intro0"); - _input->_inputMode = Input::kInputModeMenu; - - do { - _input->readInput(); - if (!_menuHelper->run()) break; - _gfx->beginFrame(); - _gfx->updateScreen(); - } while (true); + new MainMenuInputState_BR(this, _menuHelper); - delete _menuHelper; - _menuHelper = 0; + if (showSplash) { + new SplashInputState0_BR(this, _menuHelper); + new SplashInputState1_BR(this, _menuHelper); + _menuHelper->setState("intro0"); + } else { + _menuHelper->setState("mainmenu"); + } - _input->_inputMode = Input::kInputModeGame; + _input->_inputMode = Input::kInputModeMenu; } + } // namespace Parallaction diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp index 815c27bd1c..73cc1be12e 100644 --- a/engines/parallaction/gui_ns.cpp +++ b/engines/parallaction/gui_ns.cpp @@ -29,6 +29,7 @@ #include "parallaction/gui.h" #include "parallaction/input.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -41,14 +42,14 @@ protected: Common::String _nextState; uint32 _startTime; - Parallaction_ns *_vm; + Parallaction *_vm; public: - SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { + SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) { } virtual MenuInputState* run() { - uint32 curTime = g_system->getMillis(); + uint32 curTime = _vm->_system->getMillis(); if (curTime - _startTime > _timeOut) { _vm->freeBackground(); return _helper->getState(_nextState); @@ -59,14 +60,14 @@ public: virtual void enter() { _vm->_input->setMouseState(MOUSE_DISABLED); _vm->showSlide(_slideName.c_str()); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); } }; class SplashInputState0_NS : public SplashInputState_NS { public: - SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) { + SplashInputState0_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) { _slideName = "intro"; _timeOut = 2000; _nextState = "intro1"; @@ -76,7 +77,7 @@ public: class SplashInputState1_NS : public SplashInputState_NS { public: - SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { + SplashInputState1_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) { _slideName = "minintro"; _timeOut = 2000; _nextState = "chooselanguage"; @@ -111,10 +112,10 @@ class ChooseLanguageInputState_NS : public MenuInputState { static const Common::Rect _amigaLanguageSelectBlocks[4]; const Common::Rect *_blocks; - Parallaction_ns *_vm; + Parallaction *_vm; public: - ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { + ChooseLanguageInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) { _allowChoice = false; _nextState = "selectgame"; @@ -178,7 +179,7 @@ public: uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1); _vm->_gfx->showLabel(id, 60, 30); - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); } }; @@ -203,13 +204,13 @@ class SelectGameInputState_NS : public MenuInputState { uint _labels[2]; - Parallaction_ns *_vm; + Parallaction *_vm; static const char *newGameMsg[4]; static const char *loadGameMsg[4]; public: - SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { + SelectGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) { _choice = 0; _oldChoice = -1; @@ -271,10 +272,10 @@ const char *SelectGameInputState_NS::loadGameMsg[4] = { class LoadGameInputState_NS : public MenuInputState { bool _result; - Parallaction_ns *_vm; + Parallaction *_vm; public: - LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } + LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { } virtual MenuInputState* run() { if (!_result) { @@ -284,19 +285,19 @@ public: } virtual void enter() { - _result = _vm->loadGame(); + _result = _vm->_saveLoad->loadGame(); } }; class NewGameInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; static const char *introMsg3[4]; public: - NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { + NewGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -344,14 +345,15 @@ const char *NewGameInputState_NS::introMsg3[4] = { class StartDemoInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; public: - StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { + StartDemoInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) { } virtual MenuInputState* run() { _vm->scheduleLocationSwitch("fognedemo.dough"); + _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); return 0; } @@ -371,7 +373,7 @@ class SelectCharacterInputState_NS : public MenuInputState { static const Common::Rect codeSelectBlocks[9]; static const Common::Rect codeTrueBlocks[9]; - Parallaction_ns *_vm; + Parallaction *_vm; int guiGetSelectedBlock(const Common::Point &p) { @@ -388,7 +390,7 @@ class SelectCharacterInputState_NS : public MenuInputState { _vm->_gfx->invertBackground(codeTrueBlocks[selection]); _vm->_gfx->updateScreen(); _vm->beep(); - g_system->delayMillis(100); + _vm->_system->delayMillis(100); _vm->_gfx->invertBackground(codeTrueBlocks[selection]); _vm->_gfx->updateScreen(); } @@ -424,7 +426,7 @@ class SelectCharacterInputState_NS : public MenuInputState { public: - SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { + SelectCharacterInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) { _keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys; _block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1); } @@ -443,7 +445,7 @@ public: } void delay() { - if (g_system->getMillis() - _startTime < 2000) { + if (_vm->_system->getMillis() - _startTime < 2000) { return; } cleanup(); @@ -485,7 +487,7 @@ public: _vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false); _vm->_gfx->hideLabel(_labels[0]); _vm->_gfx->showLabel(_labels[1], 60, 30); - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _state = DELAY; } @@ -508,7 +510,6 @@ public: error("If you read this, either your CPU or transivity is broken (we believe the former)."); } - _vm->_inTestResult = false; _vm->cleanupGame(); _vm->scheduleLocationSwitch(_charStartLocation[character]); } @@ -555,7 +556,7 @@ public: cleanup(); - _vm->setArrowCursor(); + _vm->_input->setArrowCursor(); _vm->_input->setMouseState(MOUSE_ENABLED_SHOW); _state = CHOICE; } @@ -620,7 +621,7 @@ const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = { class ShowCreditsInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; int _current; uint32 _startTime; @@ -632,7 +633,7 @@ class ShowCreditsInputState_NS : public MenuInputState { static const Credit _credits[6]; public: - ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { + ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) { } void drawCurrentLabel() { @@ -646,14 +647,14 @@ public: virtual MenuInputState* run() { if (_current == -1) { - _startTime = g_system->getMillis(); + _startTime = _vm->_system->getMillis(); _current = 0; drawCurrentLabel(); return this; } int event = _vm->_input->getLastButtonEvent(); - uint32 curTime = g_system->getMillis(); + uint32 curTime = _vm->_system->getMillis(); if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) { _current++; _startTime = curTime; @@ -685,11 +686,11 @@ const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = { }; class EndIntroInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; bool _isDemo; public: - EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { + EndIntroInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) { _isDemo = (_vm->getFeatures() & GF_DEMO) != 0; } @@ -701,7 +702,8 @@ public: } if (_isDemo) { - _engineFlags |= kEngineQuit; + _vm->_quit = true; + _vm->quitGame(); return 0; } @@ -722,7 +724,7 @@ public: class EndPartInputState_NS : public MenuInputState { - Parallaction_ns *_vm; + Parallaction *_vm; bool _allPartsComplete; // part completion messages @@ -738,7 +740,7 @@ class EndPartInputState_NS : public MenuInputState { public: - EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { + EndPartInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) { } virtual MenuInputState* run() { @@ -758,20 +760,23 @@ public: } virtual void enter() { - _allPartsComplete = _vm->allPartsComplete(); + bool completed[3]; + _vm->_saveLoad->getGamePartProgress(completed, 3); + _allPartsComplete = (completed[0] && completed[1] && completed[2]); _vm->_input->setMouseState(MOUSE_DISABLED); + uint16 language = _vm->getInternLanguage(); uint id[4]; if (_allPartsComplete) { - id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1); - id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1); - id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1); - id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1); + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[language], 1); } else { - id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1); - id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1); - id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1); - id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1); + id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[language], 1); + id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[language], 1); + id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[language], 1); + id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[language], 1); } _vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 287618e803..c91421e15e 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -31,6 +31,58 @@ namespace Parallaction { +#define MOUSEARROW_WIDTH_NS 16 +#define MOUSEARROW_HEIGHT_NS 16 + +#define MOUSECOMBO_WIDTH_NS 32 // sizes for cursor + selected inventory item +#define MOUSECOMBO_HEIGHT_NS 32 + +struct MouseComboProperties { + int _xOffset; + int _yOffset; + int _width; + int _height; +}; +/* +// TODO: improve NS's handling of normal cursor before merging cursor code. +MouseComboProperties _mouseComboProps_NS = { + 7, // combo x offset (the icon from the inventory will be rendered from here) + 7, // combo y offset (ditto) + 32, // combo (arrow + icon) width + 32 // combo (arrow + icon) height +}; +*/ +MouseComboProperties _mouseComboProps_BR = { + 8, // combo x offset (the icon from the inventory will be rendered from here) + 8, // combo y offset (ditto) + 68, // combo (arrow + icon) width + 68 // combo (arrow + icon) height +}; + +Input::Input(Parallaction *vm) : _vm(vm) { + _gameType = _vm->getGameType(); + _transCurrentHoverItem = 0; + _hasDelayedAction = false; // actived when the character needs to move before taking an action + _mouseState = MOUSE_DISABLED; + _activeItem._index = 0; + _activeItem._id = 0; + _mouseButtons = 0; + _delayedActionZone = nullZonePtr; + + initCursors(); +} + +Input::~Input() { + if (_gameType == GType_Nippon) { + delete _mouseArrow; + } + + delete _comboArrow; + delete _dinoCursor; + delete _dougCursor; + delete _donnaCursor; +} + // FIXME: the engine has 3 event loops. The following routine hosts the main one, // and it's called from 8 different places in the code. There exist 2 more specialised // loops which could possibly be merged into this one with some effort in changing @@ -79,8 +131,9 @@ void Input::readInput() { _mousePos = e.mouse; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _engineFlags |= kEngineQuit; + _vm->_quit = true; return; default: @@ -127,9 +180,9 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) { } -void Input::updateGameInput() { +int Input::updateGameInput() { - readInput(); + int event = kEvNone; if (!isMouseEnabled() || (_engineFlags & kEngineWalking) || @@ -141,44 +194,38 @@ void Input::updateGameInput() { (_engineFlags & kEngineChangeLocation) == 0 ); - return; + return event; } if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) { - if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame; - if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame; + if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame; + if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame; } - if (_inputData._event == kEvNone) { - _inputData._mousePos = _mousePos; + if (event == kEvNone) { translateGameInput(); } + return event; } -InputData* Input::updateInput() { +int Input::updateInput() { - _inputData._event = kEvNone; + int event = kEvNone; + readInput(); switch (_inputMode) { - case kInputModeComment: - case kInputModeDialogue: - case kInputModeMenu: - readInput(); - break; - case kInputModeGame: - updateGameInput(); + event = updateGameInput(); break; case kInputModeInventory: - readInput(); updateInventoryInput(); break; } - return &_inputData; + return event; } void Input::trackMouse(ZonePtr z) { @@ -212,7 +259,7 @@ void Input::takeAction(ZonePtr z) { void Input::walkTo(const Common::Point &dest) { stopHovering(); - _vm->setArrowCursor(); + setArrowCursor(); _vm->_char.scheduleWalk(dest.x, dest.y); } @@ -252,7 +299,6 @@ bool Input::translateGameInput() { if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) { - _inputData._zone = z; if (z->_flags & kFlagsNoWalk) { // character doesn't need to walk to take specified action takeAction(z); @@ -269,7 +315,7 @@ bool Input::translateGameInput() { } _vm->beep(); - _vm->setArrowCursor(); + setArrowCursor(); return true; } @@ -285,7 +331,7 @@ void Input::enterInventoryMode() { _activeItem._index = (_activeItem._id >> 16) & 0xFFFF; _engineFlags |= kEngineDragging; } else { - _vm->setArrowCursor(); + setArrowCursor(); } } @@ -320,12 +366,12 @@ void Input::exitInventoryMode() { _vm->closeInventory(); if (pos == -1) { - _vm->setArrowCursor(); + setArrowCursor(); } else { const InventoryItem *item = _vm->getInventoryItem(pos); if (item->_index != 0) { _activeItem._id = item->_id; - _vm->setInventoryCursor(item->_index); + setInventoryCursor(item->_index); } } _vm->resumeJobs(); @@ -373,4 +419,96 @@ bool Input::isMouseEnabled() { return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE); } + +void Input::initCursors() { + + _dinoCursor = _donnaCursor = _dougCursor = 0; + + switch (_gameType) { + case GType_Nippon: + _comboArrow = _vm->_disk->loadPointer("pointer"); + _mouseArrow = new Cnv(1, MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, _resMouseArrow_NS, false); + break; + + case GType_BRA: + if (_vm->getPlatform() == Common::kPlatformPC) { + _dinoCursor = _vm->_disk->loadPointer("pointer1"); + _dougCursor = _vm->_disk->loadPointer("pointer2"); + _donnaCursor = _vm->_disk->loadPointer("pointer3"); + + Graphics::Surface *surf = new Graphics::Surface; + surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); + _comboArrow = new SurfaceToFrames(surf); + + // TODO: choose the pointer depending on the active character + // For now, we pick Donna's + _mouseArrow = _donnaCursor; + } else { + // TODO: Where are the Amiga cursors? + _mouseArrow = 0; + } + break; + + default: + warning("Input::initCursors: unknown gametype"); + } + +} + +void Input::setArrowCursor() { + + switch (_gameType) { + case GType_Nippon: + debugC(1, kDebugInput, "setting mouse cursor to arrow"); + // this stuff is needed to avoid artifacts with labels and selected items when switching cursors + stopHovering(); + _activeItem._id = 0; + _vm->_system->setMouseCursor(_mouseArrow->getData(0), MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, 0, 0, 0); + break; + + case GType_BRA: { + if (_vm->getPlatform() == Common::kPlatformAmiga) + return; + + Common::Rect r; + _mouseArrow->getRect(0, r); + _vm->_system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); + _vm->_system->showMouse(true); + _activeItem._id = 0; + break; + } + + default: + warning("Input::setArrowCursor: unknown gametype"); + } + +} + +void Input::setInventoryCursor(ItemName name) { + assert(name > 0); + + switch (_gameType) { + case GType_Nippon: { + byte *v8 = _comboArrow->getData(0); + // FIXME: destination offseting is not clear + _vm->_inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH_NS + 7, MOUSECOMBO_WIDTH_NS); + _vm->_system->setMouseCursor(v8, MOUSECOMBO_WIDTH_NS, MOUSECOMBO_HEIGHT_NS, 0, 0, 0); + break; + } + + case GType_BRA: { + byte *src = _mouseArrow->getData(0); + byte *dst = _comboArrow->getData(0); + memcpy(dst, src, _comboArrow->getSize(0)); + // FIXME: destination offseting is not clear + _vm->_inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); + _vm->_system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); + } + + default: + warning("Input::setInventoryCursor: unknown gametype"); + } + +} + } // namespace Parallaction diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index c1e912db74..e7d20c0d2e 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -41,14 +41,6 @@ enum { kMouseRightDown = 8 }; -struct InputData { - uint16 _event; - Common::Point _mousePos; - int16 _inventoryIndex; - ZonePtr _zone; - uint _label; -}; - enum MouseTriState { MOUSE_ENABLED_SHOW, MOUSE_ENABLED_HIDE, @@ -56,10 +48,7 @@ enum MouseTriState { }; class Input { - void updateGameInput(); - - // input-only - InputData _inputData; + int updateGameInput(); bool _hasKeyPressEvent; Common::KeyState _keyPressed; @@ -69,7 +58,7 @@ class Input { int16 _transCurrentHoverItem; - InputData *translateInput(); + void translateInput(); bool translateGameInput(); bool updateInventoryInput(); void takeAction(ZonePtr z); @@ -85,6 +74,17 @@ class Input { void enterInventoryMode(); void exitInventoryMode(); + int _gameType; + + static byte _resMouseArrow_NS[256]; + Frames *_mouseArrow; + Frames *_comboArrow; + Frames *_dinoCursor; + Frames *_dougCursor; + Frames *_donnaCursor; + + void initCursors(); + public: enum { kInputModeGame = 0, @@ -95,18 +95,8 @@ public: }; - Input(Parallaction *vm) : _vm(vm) { - _transCurrentHoverItem = 0; - _hasDelayedAction = false; // actived when the character needs to move before taking an action - _mouseState = MOUSE_DISABLED; - _activeItem._index = 0; - _activeItem._id = 0; - _mouseButtons = 0; - _delayedActionZone = nullZonePtr; - } - - virtual ~Input() { } - + Input(Parallaction *vm); + virtual ~Input(); void getCursorPos(Common::Point& p) { p = _mousePos; @@ -116,7 +106,7 @@ public: InventoryItem _activeItem; void readInput(); - InputData* updateInput(); + int updateInput(); void trackMouse(ZonePtr z); void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1); uint32 getLastButtonEvent() { return _mouseButtons; } @@ -129,6 +119,9 @@ public: void setMouseState(MouseTriState state); MouseTriState getMouseState(); bool isMouseEnabled(); + + void setArrowCursor(); + void setInventoryCursor(ItemName name); }; } // namespace Parallaction diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp index d2332643ed..b4776250c6 100644 --- a/engines/parallaction/objects.cpp +++ b/engines/parallaction/objects.cpp @@ -180,7 +180,6 @@ Zone::~Zone() { case kZoneDoor: free(u.door->_location); - free(u.door->_background); u.door->gfxobj->release(); delete u.door; break; @@ -191,7 +190,6 @@ Zone::~Zone() { break; case kZoneGet: - free(u.get->_backup); u.get->gfxobj->release(); delete u.get; break; diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h index 15550c65c6..431d12504e 100644 --- a/engines/parallaction/objects.h +++ b/engines/parallaction/objects.h @@ -192,23 +192,19 @@ struct Dialogue { ~Dialogue(); }; -struct GetData { // size = 24 +struct GetData { uint32 _icon; GfxObj *gfxobj; - byte *_backup; - uint16 field_14; // unused - uint16 field_16; // unused MaskBuffer _mask[2]; bool hasMask; GetData() { _icon = 0; - _backup = NULL; gfxobj = NULL; hasMask = false; } }; -struct SpeakData { // size = 36 +struct SpeakData { char _name[32]; Dialogue *_dialogue; @@ -217,30 +213,25 @@ struct SpeakData { // size = 36 _dialogue = NULL; } }; -struct ExamineData { // size = 28 +struct ExamineData { GfxObj *_cnv; - uint16 _opBase; // unused - uint16 field_12; // unused char* _description; char* _filename; ExamineData() { - _opBase = 0; _description = NULL; _filename = NULL; _cnv = NULL; } }; -struct DoorData { // size = 28 +struct DoorData { char* _location; GfxObj *gfxobj; - byte* _background; Common::Point _startPos; uint16 _startFrame; DoorData() { _location = NULL; - _background = NULL; _startFrame = 0; gfxobj = NULL; } diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index c810d22b33..828cb4d021 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -35,6 +35,7 @@ #include "parallaction/input.h" #include "parallaction/parallaction.h" #include "parallaction/debug.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -47,7 +48,6 @@ Parallaction *_vm = NULL; // public stuff char _saveData1[30] = { '\0' }; -uint16 _language = 0; uint32 _engineFlags = 0; uint16 _score = 1; @@ -66,7 +66,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam // FIXME _vm = this; - Common::File::addDefaultDirectory( _gameDataPath ); + Common::File::addDefaultDirectory(_gameDataDir); Common::addSpecialDebugLevel(kDebugDialogue, "dialogue", "Dialogues debug level"); Common::addSpecialDebugLevel(kDebugParser, "parser", "Parser debug level"); @@ -100,8 +100,6 @@ Parallaction::~Parallaction() { cleanupGui(); - delete _comboArrow; - delete _localFlagNames; delete _gfx; delete _soundMan; @@ -116,7 +114,6 @@ int Parallaction::init() { _objectsNames = NULL; _globalFlagsNames = NULL; _location._hasSound = false; - _baseTime = 0; _numLocations = 0; _location._startPosition.x = -1000; _location._startPosition.y = -1000; @@ -124,6 +121,8 @@ int Parallaction::init() { _location._comment = NULL; _location._endComment = NULL; + _quit = false; + _pathBuffer = 0; _screenSize = _screenWidth * _screenHeight; @@ -134,6 +133,7 @@ int Parallaction::init() { initInventory(); // needs to be pushed into subclass + // this needs _disk to be already setup _input = new Input(this); _gfx = new Gfx(this); @@ -147,14 +147,6 @@ int Parallaction::init() { return 0; } - -void Parallaction::clearSet(OpcodeSet &opcodes) { - for (Common::Array<const Opcode*>::iterator i = opcodes.begin(); i != opcodes.end(); ++i) - delete *i; - opcodes.clear(); -} - - void Parallaction::updateView() { if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) { @@ -163,7 +155,7 @@ void Parallaction::updateView() { _gfx->animatePalette(); _gfx->updateScreen(); - g_system->delayMillis(30); + _vm->_system->delayMillis(30); } @@ -278,7 +270,15 @@ void Parallaction::freeLocation() { return; } +void Parallaction::showSlide(const char *name, int x, int y) { + BackgroundInfo *info = new BackgroundInfo; + _disk->loadSlide(*info, name); + info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; + info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; + + _gfx->setBackground(kBackgroundSlide, info); +} void Parallaction::freeBackground() { @@ -303,22 +303,19 @@ void Parallaction::showLocationComment(const char *text, bool end) { } -void Parallaction::processInput(InputData *data) { - if (!data) { - return; - } +void Parallaction::processInput(int event) { - switch (data->_event) { + switch (event) { case kEvSaveGame: _input->stopHovering(); - saveGame(); - setArrowCursor(); + _saveLoad->saveGame(); + _input->setArrowCursor(); break; case kEvLoadGame: _input->stopHovering(); - loadGame(); - setArrowCursor(); + _saveLoad->loadGame(); + _input->setArrowCursor(); break; } @@ -328,8 +325,8 @@ void Parallaction::processInput(InputData *data) { void Parallaction::runGame() { - InputData *data = _input->updateInput(); - if (_engineFlags & kEngineQuit) + int event = _input->updateInput(); + if (quit()) return; runGuiFrame(); @@ -337,10 +334,10 @@ void Parallaction::runGame() { runCommentFrame(); if (_input->_inputMode == Input::kInputModeGame) { - processInput(data); + processInput(event); runPendingZones(); - if (_engineFlags & kEngineQuit) + if (quit()) return; if (_engineFlags & kEngineChangeLocation) { @@ -403,7 +400,7 @@ void Parallaction::doLocationEnterTransition() { pal.fadeTo(_gfx->_palette, 4); _gfx->setPalette(pal); _gfx->updateScreen(); - g_system->delayMillis(20); + _vm->_system->delayMillis(20); } _gfx->setPalette(_gfx->_palette); @@ -431,6 +428,387 @@ uint32 Parallaction::getLocationFlags() { +void Parallaction::drawAnimations() { + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n"); + + uint16 layer = 0, scale = 100; + + for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) { + + AnimationPtr anim = *it; + GfxObj *obj = anim->gfxobj; + + // Validation is performed here, so that every animation is affected, instead that only the ones + // who *own* a script. In fact, some scripts can change values in other animations. + // The right way to do this would be to enforce validation when any variable is modified from + // a script. + anim->validateScriptVars(); + + if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) { + + if (anim->_flags & kFlagsNoMasked) + layer = LAYER_FOREGROUND; + else { + if (getGameType() == GType_Nippon) { + // Layer in NS depends on where the animation is on the screen, for each animation. + layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height()); + } else { + // Layer in BRA is calculated from Z value. For characters it is the same as NS, + // but other animations can have Z set from scripts independently from their + // position on the screen. + layer = _gfx->_backgroundInfo->getLayer(anim->getZ()); + } + } + + if (getGameType() == GType_BRA) { + if (anim->_flags & (kFlagsScaled | kFlagsCharacter)) { + if (anim->getZ() <= _location._zeta0) { + if (anim->getZ() >= _location._zeta1) { + scale = ((anim->getZ() - _location._zeta1) * (100 - _location._zeta2)) / (_location._zeta0 - _location._zeta1) + _location._zeta2; + } else { + scale = _location._zeta2; + } + } + } + } + + if (obj) { + _gfx->showGfxObj(obj, true); + obj->frame = anim->getF(); + obj->x = anim->getX(); + obj->y = anim->getY(); + obj->z = anim->getZ(); + obj->layer = layer; + obj->scale = scale; + } + } + + if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsRemove; + } + + if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) { + anim->_flags &= ~kFlagsActive; + anim->_flags |= kFlagsRemove; + if (obj) { + _gfx->showGfxObj(obj, false); + } + } + } + + debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n"); + + return; +} + + +void Parallaction::showZone(ZonePtr z, bool visible) { + if (!z) { + return; + } + + if (visible) { + z->_flags &= ~kFlagsRemove; + z->_flags |= kFlagsActive; + } else { + z->_flags |= kFlagsRemove; + } + + if ((z->_type & 0xFFFF) == kZoneGet) { + _gfx->showGfxObj(z->u.get->gfxobj, visible); + + GetData *data = z->u.get; + if (data->hasMask && _gfx->_backgroundInfo->hasMask) { + if (visible) { + _gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h); + } else { + _gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h); + } + } + } +} + + +// +// ZONE TYPE: EXAMINE +// + +void Parallaction::enterCommentMode(ZonePtr z) { + if (!z) { + return; + } + + _commentZone = z; + + ExamineData *data = _commentZone->u.examine; + + if (!data->_description) { + return; + } + + // TODO: move this balloons stuff into DialogueManager and BalloonManager + if (getGameType() == GType_Nippon) { + int id; + if (data->_filename) { + if (data->_cnv == 0) { + data->_cnv = _disk->loadStatic(data->_filename); + } + + _gfx->setHalfbriteMode(true); + _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, BalloonManager::kNormalColor); + Common::Rect r; + data->_cnv->getRect(0, r); + id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2); + _gfx->setItemFrame(id, 0); + id = _gfx->setItem(_char._head, 100, 152); + _gfx->setItemFrame(id, 0); + } else { + _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, BalloonManager::kNormalColor); + id = _gfx->setItem(_char._talk, 190, 80); + _gfx->setItemFrame(id, 0); + } + } else + if (getGameType() == GType_BRA) { + _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, BalloonManager::kNormalColor); + int id = _gfx->setItem(_char._talk, 10, 80); + _gfx->setItemFrame(id, 0); + } + + _input->_inputMode = Input::kInputModeComment; +} + +void Parallaction::exitCommentMode() { + _input->_inputMode = Input::kInputModeGame; + + hideDialogueStuff(); + _gfx->setHalfbriteMode(false); + + _cmdExec->run(_commentZone->_commands, _commentZone); + _commentZone = nullZonePtr; +} + +void Parallaction::runCommentFrame() { + if (_input->_inputMode != Input::kInputModeComment) { + return; + } + + if (_input->getLastButtonEvent() == kMouseLeftUp) { + exitCommentMode(); + } +} + + +void Parallaction::runZone(ZonePtr z) { + debugC(3, kDebugExec, "runZone (%s)", z->_name); + + uint16 subtype = z->_type & 0xFFFF; + + debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); + switch(subtype) { + + case kZoneExamine: + enterCommentMode(z); + return; + + case kZoneGet: + pickupItem(z); + break; + + case kZoneDoor: + if (z->_flags & kFlagsLocked) break; + updateDoor(z, !(z->_flags & kFlagsClosed)); + break; + + case kZoneHear: + _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); + break; + + case kZoneSpeak: + enterDialogueMode(z); + return; + } + + debugC(3, kDebugExec, "runZone completed"); + + _cmdExec->run(z->_commands, z); + + return; +} + +// +// ZONE TYPE: DOOR +// +void Parallaction::updateDoor(ZonePtr z, bool close) { + z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed); + + if (z->u.door->gfxobj) { + uint frame = (close ? 0 : 1); +// z->u.door->gfxobj->setFrame(frame); + z->u.door->gfxobj->frame = frame; + } + + return; +} + + + +// +// ZONE TYPE: GET +// + +bool Parallaction::pickupItem(ZonePtr z) { + if (z->_flags & kFlagsFixed) { + return false; + } + + int slot = addInventoryItem(z->u.get->_icon); + if (slot != -1) { + showZone(z, false); + } + + return (slot != -1); +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) { + // not a special zone + if ((z->getX() != -2) && (z->getX() != -3)) { + return false; + } + + // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs + // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, + // but we need to check it separately here. The same workaround is applied in freeZones. + if ((((z->_type & 0xFFFF) == kZoneMerge) && (((x == z->u.merge->_obj1) && (y == z->u.merge->_obj2)) || ((x == z->u.merge->_obj2) && (y == z->u.merge->_obj1)))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((x == z->u.get->_icon) || (y == z->u.get->_icon)))) { + + // WORKAROUND for bug 2070751: special zones are only used in NS, to allow the + // the EXAMINE/USE action to be applied on some particular item in the inventory. + // The usage a verb requires at least an item match, so type can't be 0, as it + // was in the original code. This bug has been here since the beginning, and was + // hidden by label code, which filtered the bogus matches produced here. + + // look for action + item match + if (z->_type == type) + return true; + // look for item match, but don't accept 0 types + if (((z->_type & 0xFFFF0000) == type) && (type)) + return true; + } + + return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) { + if (z->_flags & kFlagsRemove) + return false; + + debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + + Common::Rect r; + z->getBox(r); + r.right++; // adjust border because Common::Rect doesn't include bottom-right edge + r.bottom++; + + r.grow(-1); // allows some tolerance for mouse click + + if (!r.contains(x, y)) { + + // check for special zones (items defined in common.loc) + if (checkSpecialZoneBox(z, type, x, y)) + return true; + + if (z->getX() != -1) + return false; + if ((int)x < _char._ani->getFrameX()) + return false; + if ((int)x > (_char._ani->getFrameX() + _char._ani->width())) + return false; + if ((int)y < _char._ani->getFrameY()) + return false; + if ((int)y > (_char._ani->getFrameY() + _char._ani->height())) + return false; + } + + // normal Zone + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return true; + if (z->_type == type) + return true; + if ((z->_type & 0xFFFF0000) == type) + return true; + + return false; +} + +// FIXME: input coordinates must be offseted to handle scrolling! +bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) { + if (z->_flags & kFlagsRemove) + return false; + + if ((z->_flags & kFlagsAnimLinked) == 0) + return false; + + debugC(5, kDebugExec, "checkLinkedAnimBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y); + + AnimationPtr anim = z->_linkedAnim; + Common::Rect r(anim->getFrameX(), anim->getFrameY(), anim->getFrameX() + anim->width() + 1, anim->getFrameY() + anim->height() + 1); + + if (!r.contains(x, y)) { + return false; + } + + // NOTE: the implementation of the following lines is a different in the + // original... it is working so far, though + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return true; + if (z->_type == type) + return true; + if ((z->_type & 0xFFFF0000) == type) + return true; + + return false; +} + +ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { + uint16 _di = y; + uint16 _si = x; + + for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) { + if (checkLinkedAnimBox(*it, type, x, y)) { + return *it; + } + if (checkZoneBox(*it, type, x, y)) { + return *it; + } + } + + + int16 _a, _b, _c, _d, _e, _f; + for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) { + + AnimationPtr a = *ait; + + _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation + _e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1; // _e: horizontal range + _f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1; // _f: vertical range + + _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) + _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object + _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type + + if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { + + return a; + + } + + } + + return nullZonePtr; +} + ZonePtr Parallaction::findZone(const char *name) { @@ -443,7 +821,7 @@ ZonePtr Parallaction::findZone(const char *name) { void Parallaction::freeZones() { - debugC(2, kDebugExec, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); + debugC(2, kDebugExec, "freeZones: _vm->_quit = %i", _vm->_quit); ZoneList::iterator it = _location._zones.begin(); @@ -452,7 +830,7 @@ void Parallaction::freeZones() { // NOTE : this condition has been relaxed compared to the original, to allow the engine // to retain special - needed - zones that were lost across location switches. ZonePtr z = *it; - if (((z->getY() == -1) || (z->getX() == -2)) && ((_engineFlags & kEngineQuit) == 0)) { + if (((z->getY() == -1) || (z->getX() == -2)) && (_quit == 0)) { debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name); it++; } else { @@ -514,7 +892,7 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) { _ani->setY(100); _ani->setZ(10); _ani->setF(0); - _ani->_flags = kFlagsActive | kFlagsNoName; + _ani->_flags = kFlagsActive | kFlagsNoName | kFlagsCharacter; _ani->_type = kZoneYou; strncpy(_ani->_name, "yourself", ZONENAME_LENGTH); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index fb004a25b7..d7add635cd 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -29,6 +29,7 @@ #include "common/str.h" #include "common/stack.h" #include "common/array.h" +#include "common/func.h" #include "common/savefile.h" #include "engines/engine.h" @@ -44,8 +45,6 @@ #define PATH_LEN 200 -extern OSystem *g_system; - namespace Parallaction { enum { @@ -71,35 +70,7 @@ enum { }; -// high values mean high priority - -enum { - kPriority0 = 0, - kPriority1 = 1, - kPriority2 = 2, - kPriority3 = 3, - kPriority4 = 4, - kPriority5 = 5, - kPriority6 = 6, - kPriority7 = 7, - kPriority8 = 8, - kPriority9 = 9, - kPriority10 = 10, - kPriority11 = 11, - kPriority12 = 12, - kPriority13 = 13, - kPriority14 = 14, - kPriority15 = 15, - kPriority16 = 16, - kPriority17 = 17, - kPriority18 = 18, - kPriority19 = 19, - kPriority20 = 20, - kPriority21 = 21 -}; - enum EngineFlags { - kEngineQuit = (1 << 0), kEnginePauseJobs = (1 << 1), kEngineWalking = (1 << 3), kEngineChangeLocation = (1 << 4), @@ -116,10 +87,6 @@ enum { kEvLoadGame = 4000 }; -enum { - kCursorArrow = -1 -}; - enum ParallactionGameType { GType_Nippon = 1, GType_BRA @@ -130,10 +97,8 @@ struct PARALLACTIONGameDescription; -extern uint16 _mouseButtons; extern char _password[8]; extern uint16 _score; -extern uint16 _language; extern uint32 _engineFlags; extern char _saveData1[]; extern uint32 _globalFlags; @@ -238,6 +203,7 @@ public: }; +class SaveLoad; #define NUM_LOCATIONS 120 @@ -245,231 +211,148 @@ class Parallaction : public Engine { friend class Debugger; public: - - Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); - ~Parallaction(); - - int init(); - - virtual bool loadGame() = 0; - virtual bool saveGame() = 0; - - Input *_input; - - void processInput(InputData* data); - - void pauseJobs(); - void resumeJobs(); - - ZonePtr findZone(const char *name); - ZonePtr hitZone(uint32 type, uint16 x, uint16 y); - void runZone(ZonePtr z); - void freeZones(); - - AnimationPtr findAnimation(const char *name); - void freeAnimations(); - - void setBackground(const char *background, const char *mask, const char *path); - void freeBackground(); - - Table *_globalFlagsNames; - Table *_objectsNames; - Table *_callableNames; - Table *_localFlagNames; - -public: int getGameType() const; uint32 getFeatures() const; Common::Language getLanguage() const; Common::Platform getPlatform() const; +protected: // members + bool detectGame(void); + private: const PARALLACTIONGameDescription *_gameDescription; + uint16 _language; public: + Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc); + ~Parallaction(); + + int init(); + // info int32 _screenWidth; int32 _screenHeight; int32 _screenSize; - PathBuffer *_pathBuffer; - + // subsystems + Gfx *_gfx; + Disk *_disk; + Input *_input; SoundMan *_soundMan; + Debugger *_debugger; + SaveLoad *_saveLoad; + MenuInputHelper *_menuHelper; + Common::RandomSource _rnd; - Gfx* _gfx; - Disk* _disk; + // fonts + Font *_labelFont; + Font *_menuFont; + Font *_introFont; + Font *_dialogueFont; - CommandExec* _cmdExec; - ProgramExec* _programExec; + // game utilities + Table *_globalFlagsNames; + Table *_objectsNames; + Table *_callableNames; + Table *_localFlagNames; + CommandExec *_cmdExec; + ProgramExec *_programExec; + PathBuffer *_pathBuffer; + Inventory *_inventory; + BalloonManager *_balloonMan; + DialogueManager *_dialogueMan; + InventoryRenderer *_inventoryRenderer; + + // game data Character _char; - - void setLocationFlags(uint32 flags); - void clearLocationFlags(uint32 flags); - void toggleLocationFlags(uint32 flags); - uint32 getLocationFlags(); - uint32 _localFlags[NUM_LOCATIONS]; char _locationNames[NUM_LOCATIONS][32]; int16 _currentLocationIndex; uint16 _numLocations; Location _location; - ZonePtr _activeZone; + char _characterName1[50]; // only used in changeCharacter + ZonePtr _zoneTrap; + ZonePtr _commentZone; + bool _quit; /* The only reason this flag exists is for freeZones() to properly + * delete all zones when necessary. THIS FLAG IS NOT THE ENGINE QUIT FLAG, + * use _eventMan->shouldQuit() for that. + */ - Font *_labelFont; - Font *_menuFont; - Font *_introFont; - Font *_dialogueFont; - - Common::RandomSource _rnd; - - Debugger *_debugger; - Frames *_comboArrow; - - -protected: // data - uint32 _baseTime; - char _characterName1[50]; // only used in changeCharacter - - Common::String _saveFileName; - - -protected: // members - bool detectGame(void); - - void initGlobals(); - void runGame(); - void updateView(); - - void doLocationEnterTransition(); - virtual void changeLocation(char *location) = 0; - virtual void runPendingZones() = 0; - void allocateLocationSlot(const char *name); - void finalizeLocationParsing(); - void freeLocation(); - void showLocationComment(const char *text, bool end); - - void displayComment(ExamineData *data); - - void freeCharacter(); - - bool pickupItem(ZonePtr z); - - void clearSet(OpcodeSet &opcodes); - +protected: + void runGame(); + void runGuiFrame(); + void cleanupGui(); + void runDialogueFrame(); + void exitDialogueMode(); + void runCommentFrame(); + void enterCommentMode(ZonePtr z); + void exitCommentMode(); + void processInput(int event); + void updateView(); + void drawAnimations(); + void freeCharacter(); + void freeLocation(); + void doLocationEnterTransition(); + void allocateLocationSlot(const char *name); + void finalizeLocationParsing(); + void showLocationComment(const char *text, bool end); + void setupBalloonManager(); public: - void scheduleLocationSwitch(const char *location); - virtual void changeCharacter(const char *name) = 0; - - virtual void callFunction(uint index, void* parm) { } - - virtual void setArrowCursor() = 0; - virtual void setInventoryCursor(ItemName name) = 0; - - virtual void parseLocation(const char* name) = 0; - - void updateDoor(ZonePtr z, bool close); - - virtual void drawAnimations() = 0; - - void beep(); - - ZonePtr _zoneTrap; - PathBuilder* getPathBuilder(Character *ch); + void beep(); + void pauseJobs(); + void resumeJobs(); + void hideDialogueStuff(); + uint getInternLanguage(); + void setInternLanguage(uint id); + void enterDialogueMode(ZonePtr z); + void scheduleLocationSwitch(const char *location); + void showSlide(const char *name, int x = 0, int y = 0); public: -// const char **_zoneFlagNamesRes; -// const char **_zoneTypeNamesRes; -// const char **_commandsNamesRes; - const char **_callableNamesRes; - const char **_instructionNamesRes; - - void highlightInventoryItem(ItemPosition pos); - int16 getHoverInventoryItem(int16 x, int16 y); - int addInventoryItem(ItemName item); - int addInventoryItem(ItemName item, uint32 value); - void dropItem(uint16 v); - bool isItemInInventory(int32 v); - const InventoryItem* getInventoryItem(int16 pos); - int16 getInventoryItemIndex(int16 pos); - void initInventory(); - void destroyInventory(); - void cleanInventory(bool keepVerbs = true); - void openInventory(); - void closeInventory(); - - Inventory *_inventory; - InventoryRenderer *_inventoryRenderer; - - BalloonManager *_balloonMan; - - void setupBalloonManager(); - - void hideDialogueStuff(); - DialogueManager *_dialogueMan; - void enterDialogueMode(ZonePtr z); - void exitDialogueMode(); - void runDialogueFrame(); - - MenuInputHelper *_menuHelper; - void runGuiFrame(); - void cleanupGui(); - - ZonePtr _commentZone; - void enterCommentMode(ZonePtr z); - void exitCommentMode(); - void runCommentFrame(); - - void setInternLanguage(uint id); - uint getInternLanguage(); + void setLocationFlags(uint32 flags); + void clearLocationFlags(uint32 flags); + void toggleLocationFlags(uint32 flags); + uint32 getLocationFlags(); + bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y); + bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y); + bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y); + ZonePtr findZone(const char *name); + ZonePtr hitZone(uint32 type, uint16 x, uint16 y); + void runZone(ZonePtr z); + void freeZones(); + bool pickupItem(ZonePtr z); + void updateDoor(ZonePtr z, bool close); + void showZone(ZonePtr z, bool visible); + AnimationPtr findAnimation(const char *name); + void freeAnimations(); + void setBackground(const char *background, const char *mask, const char *path); + void freeBackground(); + void highlightInventoryItem(ItemPosition pos); + int16 getHoverInventoryItem(int16 x, int16 y); + int addInventoryItem(ItemName item); + int addInventoryItem(ItemName item, uint32 value); + void dropItem(uint16 v); + bool isItemInInventory(int32 v); + const InventoryItem* getInventoryItem(int16 pos); + int16 getInventoryItemIndex(int16 pos); + void initInventory(); + void destroyInventory(); + void cleanInventory(bool keepVerbs = true); + void openInventory(); + void closeInventory(); - void showZone(ZonePtr z, bool visible); + virtual void parseLocation(const char* name) = 0; + virtual void changeLocation(char *location) = 0; + virtual void changeCharacter(const char *name) = 0; + virtual void callFunction(uint index, void* parm) = 0; + virtual void runPendingZones() = 0; + virtual void cleanupGame() = 0; }; -class LocationName { - - Common::String _slide; - Common::String _character; - Common::String _location; - - bool _hasCharacter; - bool _hasSlide; - char *_buf; - -public: - LocationName(); - ~LocationName(); - - void bind(const char*); - - const char *location() const { - return _location.c_str(); - } - - bool hasCharacter() const { - return _hasCharacter; - } - - const char *character() const { - return _character.c_str(); - } - - bool hasSlide() const { - return _hasSlide; - } - - const char *slide() const { - return _slide.c_str(); - } - - const char *c_str() const { - return _buf; - } -}; - class Parallaction_ns : public Parallaction { @@ -481,70 +364,45 @@ public: int go(); public: - typedef void (Parallaction_ns::*Callable)(void*); - - virtual void callFunction(uint index, void* parm); + virtual void parseLocation(const char *filename); + virtual void changeLocation(char *location); + virtual void changeCharacter(const char *name); + virtual void callFunction(uint index, void* parm); + virtual void runPendingZones(); + virtual void cleanupGame(); - bool loadGame(); - bool saveGame(); - void switchBackground(const char* background, const char* mask); - void showSlide(const char *name, int x = 0, int y = 0); - void setArrowCursor(); - - // TODO: this should be private!!!!!!! - bool _inTestResult; - void cleanupGame(); - bool allPartsComplete(); + void switchBackground(const char* background, const char* mask); private: - LocationParser_ns *_locationParser; - ProgramParser_ns *_programParser; - - void initFonts(); - void freeFonts(); - void renameOldSavefiles(); - Common::String genSaveFileName(uint slot, bool oldStyle = false); - Common::InSaveFile *getInSaveFile(uint slot); - Common::OutSaveFile *getOutSaveFile(uint slot); - void setPartComplete(const Character& character); + bool _inTestResult; + LocationParser_ns *_locationParser; + ProgramParser_ns *_programParser; private: - void changeLocation(char *location); - void changeCharacter(const char *name); - void runPendingZones(); - - void setInventoryCursor(ItemName name); - - - void doLoadGame(uint16 slot); - void doSaveGame(uint16 slot, const char* name); - int buildSaveFileList(Common::StringList& l); - int selectSaveFile(uint16 arg_0, const char* caption, const char* button); - - void initResources(); - void initCursors(); - - static byte _resMouseArrow[256]; - byte *_mouseArrow; - - static const Callable _dosCallables[25]; - static const Callable _amigaCallables[25]; + void initFonts(); + void freeFonts(); + void initResources(); + void startGui(); + void startCreditSequence(); + void startEndPartSequence(); + void loadProgram(AnimationPtr a, const char *filename); - /* - game callables data members - */ + // callables data + typedef void (Parallaction_ns::*Callable)(void*); + const Callable *_callables; ZonePtr _moveSarcZone0; ZonePtr _moveSarcZone1; uint16 num_foglie; int16 _introSarcData1; uint16 _introSarcData2; // sarcophagus stuff to be saved uint16 _introSarcData3; // sarcophagus stuff to be saved - ZonePtr _moveSarcZones[5]; ZonePtr _moveSarcExaZones[5]; AnimationPtr _rightHandAnim; + static const Callable _dosCallables[25]; + static const Callable _amigaCallables[25]; // common callables void _c_play_boogie(void*); @@ -578,20 +436,6 @@ private: void _c_startMusic(void*); void _c_closeMusic(void*); void _c_HBOn(void*); - - const Callable *_callables; - -protected: - void drawAnimations(); - - void parseLocation(const char *filename); - void loadProgram(AnimationPtr a, const char *filename); - - void selectStartLocation(); - - void startGui(); - void startCreditSequence(); - void startEndPartSequence(); }; @@ -600,8 +444,6 @@ protected: class Parallaction_br : public Parallaction_ns { - typedef Parallaction_ns Super; - public: Parallaction_br(OSystem* syst, const PARALLACTIONGameDescription *gameDesc) : Parallaction_ns(syst, gameDesc) { } ~Parallaction_br(); @@ -610,83 +452,55 @@ public: int go(); public: - typedef void (Parallaction_br::*Callable)(void*); + virtual void parseLocation(const char* name); + virtual void changeLocation(char *location); + virtual void changeCharacter(const char *name); virtual void callFunction(uint index, void* parm); - void changeCharacter(const char *name); + virtual void runPendingZones(); + virtual void cleanupGame(); + + void setupSubtitles(char *s, char *s2, int y); void clearSubtitles(); - public: Table *_countersNames; - const char **_audioCommandsNamesRes; - + static const char *_partNames[]; int _part; - int _progress; - #if 0 // disabled since I couldn't find any references to lip sync in the scripts int16 _lipSyncVal; uint _subtitleLipSync; #endif int _subtitleY; int _subtitle[2]; - ZonePtr _activeZone2; - int32 _counters[32]; - uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES]; - void startPart(uint part); - void setArrowCursor(); + private: LocationParser_br *_locationParser; ProgramParser_br *_programParser; - void initResources(); - void initFonts(); - void freeFonts(); - - void setInventoryCursor(ItemName name); - - void changeLocation(char *location); - void runPendingZones(); - - void initPart(); - void freePart(); - - void initCursors(); - - Frames *_dinoCursor; - Frames *_dougCursor; - Frames *_donnaCursor; - Frames *_mouseArrow; - - - static const char *_partNames[]; - - void startGui(); +private: + void initResources(); + void initFonts(); + void freeFonts(); + void freeLocation(); + void loadProgram(AnimationPtr a, const char *filename); + void startGui(bool showSplash); + typedef void (Parallaction_br::*Callable)(void*); + const Callable *_callables; static const Callable _dosCallables[6]; + // dos callables void _c_blufade(void*); void _c_resetpalette(void*); void _c_ferrcycle(void*); void _c_lipsinc(void*); void _c_albcycle(void*); void _c_password(void*); - - const Callable *_callables; - - void parseLocation(const char* name); - void loadProgram(AnimationPtr a, const char *filename); - -#if 0 - void jobWaitRemoveLabelJob(void *parm, Job *job); - void jobPauseSfx(void *parm, Job *job); - void jobStopFollower(void *parm, Job *job); - void jobScroll(void *parm, Job *job); -#endif }; // FIXME: remove global diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index bb8ddc5654..a06fba43f9 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -28,31 +28,11 @@ #include "parallaction/parallaction.h" #include "parallaction/input.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" namespace Parallaction { -struct MouseComboProperties { - int _xOffset; - int _yOffset; - int _width; - int _height; -}; -/* -// TODO: improve NS's handling of normal cursor before merging cursor code. -MouseComboProperties _mouseComboProps_NS = { - 7, // combo x offset (the icon from the inventory will be rendered from here) - 7, // combo y offset (ditto) - 32, // combo (arrow + icon) width - 32 // combo (arrow + icon) height -}; -*/ -MouseComboProperties _mouseComboProps_BR = { - 8, // combo x offset (the icon from the inventory will be rendered from here) - 8, // combo y offset (ditto) - 68, // combo (arrow + icon) width - 68 // combo (arrow + icon) height -}; const char *Parallaction_br::_partNames[] = { "PART0", @@ -62,14 +42,6 @@ const char *Parallaction_br::_partNames[] = { "PART4" }; -const char *partFirstLocation[] = { - "intro", - "museo", - "start", - "bolscoi", - "treno" -}; - int Parallaction_br::init() { _screenWidth = 640; @@ -96,7 +68,6 @@ int Parallaction_br::init() { initResources(); initFonts(); - initCursors(); _locationParser = new LocationParser_br(this); _locationParser->init(); _programParser = new ProgramParser_br(this); @@ -112,6 +83,8 @@ int Parallaction_br::init() { _subtitle[0] = -1; _subtitle[1] = -1; + _saveLoad = new SaveLoad_br(this, _saveFileMan); + Parallaction::init(); return 0; @@ -119,12 +92,6 @@ int Parallaction_br::init() { Parallaction_br::~Parallaction_br() { freeFonts(); - - delete _dinoCursor; - delete _dougCursor; - delete _donnaCursor; - - delete _mouseArrow; } void Parallaction_br::callFunction(uint index, void* parm) { @@ -135,25 +102,27 @@ void Parallaction_br::callFunction(uint index, void* parm) { int Parallaction_br::go() { - if (getFeatures() & GF_DEMO) { - startPart(1); - } else { - startGui(); - } + bool splash = true; - while ((_engineFlags & kEngineQuit) == 0) { + while (!quit()) { + + if (getFeatures() & GF_DEMO) { + scheduleLocationSwitch("camalb.1"); + _input->_inputMode = Input::kInputModeGame; + } else { + startGui(splash); + // don't show splash after first time + splash = false; + } // initCharacter(); - _input->_inputMode = Input::kInputModeGame; - while ((_engineFlags & (kEngineReturn | kEngineQuit)) == 0) { + while (((_engineFlags & kEngineReturn) == 0) && (!quit())) { runGame(); } _engineFlags &= ~kEngineReturn; - freePart(); -// freeCharacter(); - + cleanupGame(); } return 0; @@ -169,70 +138,6 @@ void Parallaction_br::freeFonts() { return; } -void Parallaction_br::initCursors() { - - if (getPlatform() == Common::kPlatformPC) { - _dinoCursor = _disk->loadPointer("pointer1"); - _dougCursor = _disk->loadPointer("pointer2"); - _donnaCursor = _disk->loadPointer("pointer3"); - - Graphics::Surface *surf = new Graphics::Surface; - surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1); - _comboArrow = new SurfaceToFrames(surf); - - // TODO: choose the pointer depending on the active character - // For now, we pick Donna's - _mouseArrow = _donnaCursor; - } else { - // TODO: Where are the Amiga cursors? - } - -} - -void Parallaction_br::initPart() { - - memset(_counters, 0, ARRAYSIZE(_counters)); - - _globalFlagsNames = _disk->loadTable("global"); - _objectsNames = _disk->loadTable("objects"); - _countersNames = _disk->loadTable("counters"); - - // TODO: maybe handle this into Disk - if (getPlatform() == Common::kPlatformPC) { - _char._objs = _disk->loadObjects("icone.ico"); - } else { - _char._objs = _disk->loadObjects("icons.ico"); - } - -} - -void Parallaction_br::freePart() { - - delete _globalFlagsNames; - delete _objectsNames; - delete _countersNames; - - _globalFlagsNames = 0; - _objectsNames = 0; - _countersNames = 0; -} - -void Parallaction_br::startPart(uint part) { - _part = part; - _disk->selectArchive(_partNames[_part]); - - initPart(); - - if (getFeatures() & GF_DEMO) { - strcpy(_location._name, "camalb"); - } else { - strcpy(_location._name, partFirstLocation[_part]); - } - - parseLocation("common"); - changeLocation(_location._name); - -} void Parallaction_br::runPendingZones() { ZonePtr z; @@ -260,8 +165,7 @@ void Parallaction_br::runPendingZones() { } } - -void Parallaction_br::changeLocation(char *location) { +void Parallaction_br::freeLocation() { // free open location stuff clearSubtitles(); @@ -279,27 +183,75 @@ void Parallaction_br::changeLocation(char *location) { _location._animations.push_front(_char._ani); -// free(_location._comment); -// _location._comment = 0; + free(_location._comment); + _location._comment = 0; _location._commands.clear(); _location._aCommands.clear(); +} + +void Parallaction_br::cleanupGame() { + freeLocation(); + +// freeCharacter(); + + delete _globalFlagsNames; + delete _objectsNames; + delete _countersNames; + + _globalFlagsNames = 0; + _objectsNames = 0; + _countersNames = 0; +} + + +void Parallaction_br::changeLocation(char *location) { + char *partStr = strrchr(location, '.'); + if (partStr) { + int n = partStr - location; + strncpy(_location._name, location, n); + _location._name[n] = '\0'; + + _part = atoi(++partStr); + if (getFeatures() & GF_DEMO) { + assert(_part == 1); + } else { + assert(_part >= 0 && _part <= 4); + } + + _disk->selectArchive(_partNames[_part]); + + memset(_counters, 0, ARRAYSIZE(_counters)); + + _globalFlagsNames = _disk->loadTable("global"); + _objectsNames = _disk->loadTable("objects"); + _countersNames = _disk->loadTable("counters"); + + // TODO: maybe handle this into Disk + if (getPlatform() == Common::kPlatformPC) { + _char._objs = _disk->loadObjects("icone.ico"); + } else { + _char._objs = _disk->loadObjects("icons.ico"); + } + + parseLocation("common"); + } + + freeLocation(); // load new location parseLocation(location); - - // kFlagsRemove is cleared because the character defaults to visible on new locations - // script command can hide the character, anyway, so that's why the flag is cleared - // before _location._commands are executed + // kFlagsRemove is cleared because the character is visible by default. + // Commands can hide the character, anyway. _char._ani->_flags &= ~kFlagsRemove; - _cmdExec->run(_location._commands); -// doLocationEnterTransition(); + + doLocationEnterTransition(); + _cmdExec->run(_location._aCommands); _engineFlags &= ~kEngineChangeLocation; } - // FIXME: Parallaction_br::parseLocation() is now a verbatim copy of the same routine from Parallaction_ns. void Parallaction_br::parseLocation(const char *filename) { debugC(1, kDebugParser, "parseLocation('%s')", filename); @@ -359,30 +311,5 @@ void Parallaction_br::changeCharacter(const char *name) { } -void Parallaction_br::setArrowCursor() { - // FIXME: Where are the Amiga cursors? - if (getPlatform() == Common::kPlatformAmiga) - return; - - Common::Rect r; - _mouseArrow->getRect(0, r); - - _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0); - _system->showMouse(true); - - _input->_activeItem._id = 0; -} - -void Parallaction_br::setInventoryCursor(ItemName name) { - assert(name > 0); - - byte *src = _mouseArrow->getData(0); - byte *dst = _comboArrow->getData(0); - memcpy(dst, src, _comboArrow->getSize(0)); - - // FIXME: destination offseting is not clear - _inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width); - _system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0); -} } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index 61f2859e8a..8e11931c28 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -29,27 +29,61 @@ #include "parallaction/parallaction.h" #include "parallaction/input.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" namespace Parallaction { -#define MOUSEARROW_WIDTH 16 -#define MOUSEARROW_HEIGHT 16 +class LocationName { -#define MOUSECOMBO_WIDTH 32 // sizes for cursor + selected inventory item -#define MOUSECOMBO_HEIGHT 32 + Common::String _slide; + Common::String _character; + Common::String _location; -LocationName::LocationName() { - _buf = 0; - _hasSlide = false; - _hasCharacter = false; -} + bool _hasCharacter; + bool _hasSlide; + char *_buf; + +public: + LocationName() { + _buf = 0; + _hasSlide = false; + _hasCharacter = false; + } + + ~LocationName() { + free(_buf); + } + + void bind(const char*); + + const char *location() const { + return _location.c_str(); + } + + bool hasCharacter() const { + return _hasCharacter; + } + + const char *character() const { + return _character.c_str(); + } + + bool hasSlide() const { + return _hasSlide; + } + + const char *slide() const { + return _slide.c_str(); + } + + const char *c_str() const { + return _buf; + } +}; -LocationName::~LocationName() { - free(_buf); -} /* @@ -135,7 +169,6 @@ int Parallaction_ns::init() { initResources(); initFonts(); - initCursors(); _locationParser = new LocationParser_ns(this); _locationParser->init(); _programParser = new ProgramParser_ns(this); @@ -156,6 +189,8 @@ int Parallaction_ns::init() { _location._animations.push_front(_char._ani); + _saveLoad = new SaveLoad_ns(this, _saveFileMan); + Parallaction::init(); return 0; @@ -181,32 +216,6 @@ void Parallaction_ns::freeFonts() { } -void Parallaction_ns::initCursors() { - _comboArrow = _disk->loadPointer("pointer"); - _mouseArrow = _resMouseArrow; -} - -void Parallaction_ns::setArrowCursor() { - - debugC(1, kDebugInput, "setting mouse cursor to arrow"); - - // this stuff is needed to avoid artifacts with labels and selected items when switching cursors - _input->stopHovering(); - _input->_activeItem._id = 0; - - _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0); -} - -void Parallaction_ns::setInventoryCursor(ItemName name) { - assert(name > 0); - - byte *v8 = _comboArrow->getData(0); - - // FIXME: destination offseting is not clear - _inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH); - _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0); -} - void Parallaction_ns::callFunction(uint index, void* parm) { assert(index < 25); // magic value 25 is maximum # of callables for Nippon Safes @@ -216,13 +225,13 @@ void Parallaction_ns::callFunction(uint index, void* parm) { int Parallaction_ns::go() { - renameOldSavefiles(); + _saveLoad->renameOldSavefiles(); _globalFlagsNames = _disk->loadTable("global"); startGui(); - while ((_engineFlags & kEngineQuit) == 0) { + while (!quit()) { runGame(); } @@ -242,7 +251,7 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask) v2 += 4; } - g_system->delayMillis(20); + _vm->_system->delayMillis(20); _gfx->setPalette(pal); _gfx->updateScreen(); } @@ -253,16 +262,6 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask) } -void Parallaction_ns::showSlide(const char *name, int x, int y) { - BackgroundInfo *info = new BackgroundInfo; - _disk->loadSlide(*info, name); - - info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x; - info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y; - - _gfx->setBackground(kBackgroundSlide, info); -} - void Parallaction_ns::runPendingZones() { if (_activeZone) { ZonePtr z = _activeZone; // speak Zone or sound @@ -287,7 +286,7 @@ void Parallaction_ns::changeLocation(char *location) { _zoneTrap = nullZonePtr; - setArrowCursor(); + _input->setArrowCursor(); _gfx->showGfxObj(_char._ani->gfxobj, false); _location._animations.remove(_char._ani); @@ -428,6 +427,7 @@ void Parallaction_ns::changeCharacter(const char *name) { } void Parallaction_ns::cleanupGame() { + _inTestResult = false; _engineFlags &= ~kEngineTransformedDonna; @@ -440,18 +440,22 @@ void Parallaction_ns::cleanupGame() { memset(_locationNames, 0, sizeof(_locationNames)); // this flag tells freeZones to unconditionally remove *all* Zones - _engineFlags |= kEngineQuit; + _vm->_quit = true; freeZones(); freeAnimations(); // this dangerous flag can now be cleared - _engineFlags &= ~kEngineQuit; + _vm->_quit = false; // main character animation is restored _location._animations.push_front(_char._ani); _score = 0; + _soundMan->stopMusic(); + _introSarcData3 = 200; + _introSarcData2 = 1; + return; } diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index 8e30a631e4..a475f5701a 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -183,13 +183,12 @@ uint16 Script::readLineToken(bool errorOnEOF) { clearTokens(); - bool inBlockComment = false, inLineComment; + bool inBlockComment = false; char buf[200]; char *line = NULL; + char *start; do { - inLineComment = false; - line = readLine(buf, 200); if (line == NULL) { @@ -198,21 +197,27 @@ uint16 Script::readLineToken(bool errorOnEOF) { else return 0; } - line = Common::ltrim(line); + start = Common::ltrim(line); - if (isCommentLine(line)) { - inLineComment = true; + if (isCommentLine(start)) { + // ignore this line + start[0] = '\0'; } else - if (isStartOfCommentBlock(line)) { + if (isStartOfCommentBlock(start)) { + // mark this and the following lines as comment inBlockComment = true; } else - if (isEndOfCommentBlock(line)) { + if (isEndOfCommentBlock(start)) { + // comment is finished, so stop ignoring inBlockComment = false; + // the current line must be skipped, though, + // as it contains the end-of-comment marker + start[0] = '\0'; } - } while (inLineComment || inBlockComment || strlen(line) == 0); + } while (inBlockComment || strlen(start) == 0); - return fillTokens(line); + return fillTokens(start); } @@ -403,7 +408,9 @@ void PreProcessor::preprocessScript(Script &script, StatementList &list) { break; StatementDef *def = findDef(_tokens[0]); - assert(def); + if (!def) { + error("PreProcessor::preprocessScript: unknown statement '%s' found\n", _tokens[0]); + } text = def->makeLine(script); int score = getDefScore(def); diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index e622bfd81f..f0cc448518 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -27,6 +27,7 @@ #define PARALLACTION_PARSER_H #include "common/stream.h" +#include "common/stack.h" #include "parallaction/objects.h" #include "parallaction/walk.h" @@ -455,7 +456,7 @@ public: } bool eos() const { - return _pos == _size; + return _pos == _size; // FIXME (eos definition change) } }; diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp index 20800abc33..4b11c5caa4 100644 --- a/engines/parallaction/parser_br.cpp +++ b/engines/parallaction/parser_br.cpp @@ -497,7 +497,7 @@ DECLARE_LOCATION_PARSER(zeta) { _vm->_location._zeta1 = atoi(_tokens[2]); if (_tokens[3][0] != '\0') { - _vm->_location._zeta2 = atoi(_tokens[1]); + _vm->_location._zeta2 = atoi(_tokens[3]); } else { _vm->_location._zeta2 = 50; } diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index 44613c970c..9a787d7f00 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -31,6 +31,7 @@ #include "gui/message.h" #include "parallaction/parallaction.h" +#include "parallaction/saveload.h" #include "parallaction/sound.h" @@ -57,12 +58,11 @@ protected: GUI::StaticTextWidget *_time; GUI::StaticTextWidget *_playtime; GUI::ContainerWidget *_container; - Parallaction_ns *_vm; uint8 _fillR, _fillG, _fillB; public: - SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine); + SaveLoadChooser(const String &title, const String &buttonLabel); ~SaveLoadChooser(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); @@ -73,34 +73,39 @@ public: virtual void reflowLayout(); }; -Common::String Parallaction_ns::genSaveFileName(uint slot, bool oldStyle) { +Common::String SaveLoad_ns::genOldSaveFileName(uint slot) { assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); char s[20]; - sprintf(s, (oldStyle ? "game.%i" : "nippon.%.3d"), slot ); + sprintf(s, "game.%i", slot); return Common::String(s); } -Common::InSaveFile *Parallaction_ns::getInSaveFile(uint slot) { + +Common::String SaveLoad::genSaveFileName(uint slot) { + assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT); + + char s[20]; + sprintf(s, "%s.%.3d", _saveFilePrefix.c_str(), slot); + + return Common::String(s); +} + +Common::InSaveFile *SaveLoad::getInSaveFile(uint slot) { Common::String name = genSaveFileName(slot); return _saveFileMan->openForLoading(name.c_str()); } -Common::OutSaveFile *Parallaction_ns::getOutSaveFile(uint slot) { +Common::OutSaveFile *SaveLoad::getOutSaveFile(uint slot) { Common::String name = genSaveFileName(slot); return _saveFileMan->openForSaving(name.c_str()); } -void Parallaction_ns::doLoadGame(uint16 slot) { - - _soundMan->stopMusic(); +void SaveLoad_ns::doLoadGame(uint16 slot) { - cleanupGame(); - - _introSarcData3 = 200; - _introSarcData2 = 1; + _vm->cleanupGame(); Common::InSaveFile *f = getInSaveFile(slot); if (!f) return; @@ -109,77 +114,77 @@ void Parallaction_ns::doLoadGame(uint16 slot) { char n[16]; char l[16]; - f->readLine(s, 199); + f->readLine_OLD(s, 199); - f->readLine(n, 15); + f->readLine_OLD(n, 15); - f->readLine(l, 15); + f->readLine_OLD(l, 15); - f->readLine(s, 15); - _location._startPosition.x = atoi(s); + f->readLine_OLD(s, 15); + _vm->_location._startPosition.x = atoi(s); - f->readLine(s, 15); - _location._startPosition.y = atoi(s); + f->readLine_OLD(s, 15); + _vm->_location._startPosition.y = atoi(s); - f->readLine(s, 15); + f->readLine_OLD(s, 15); _score = atoi(s); - f->readLine(s, 15); + f->readLine_OLD(s, 15); _globalFlags = atoi(s); - f->readLine(s, 15); + f->readLine_OLD(s, 15); // TODO (LIST): unify (and parametrize) calls to freeZones. // We aren't calling freeAnimations because it is not needed, since // kChangeLocation will trigger a complete deletion. Anyway, we still - // need to invoke freeZones here with kEngineQuit set, because the + // need to invoke freeZones here with _quit set, because the // call in changeLocation preserve certain zones. - _engineFlags |= kEngineQuit; - freeZones(); - _engineFlags &= ~kEngineQuit; + _vm->_quit = true; + _vm->freeZones(); + _vm->_quit = false; - _numLocations = atoi(s); + _vm->_numLocations = atoi(s); uint16 _si; - for (_si = 0; _si < _numLocations; _si++) { - f->readLine(s, 20); + for (_si = 0; _si < _vm->_numLocations; _si++) { + f->readLine_OLD(s, 20); s[strlen(s)] = '\0'; - strcpy(_locationNames[_si], s); + strcpy(_vm->_locationNames[_si], s); - f->readLine(s, 15); - _localFlags[_si] = atoi(s); + f->readLine_OLD(s, 15); + _vm->_localFlags[_si] = atoi(s); } - cleanInventory(false); + _vm->cleanInventory(false); ItemName name; uint32 value; for (_si = 0; _si < 30; _si++) { - f->readLine(s, 15); + f->readLine_OLD(s, 15); value = atoi(s); - f->readLine(s, 15); + f->readLine_OLD(s, 15); name = atoi(s); - addInventoryItem(name, value); + _vm->addInventoryItem(name, value); } delete f; // force reload of character to solve inventory // bugs, but it's a good maneuver anyway - strcpy(_characterName1, "null"); + strcpy(_vm->_characterName1, "null"); char tmp[PATH_LEN]; sprintf(tmp, "%s.%s" , l, n); - scheduleLocationSwitch(tmp); + _vm->scheduleLocationSwitch(tmp); return; } -void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { +void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) { Common::OutSaveFile *f = getOutSaveFile(slot); if (f == 0) { @@ -202,30 +207,30 @@ void Parallaction_ns::doSaveGame(uint16 slot, const char* name) { f->writeString(s); f->writeString("\n"); - sprintf(s, "%s\n", _char.getFullName()); + sprintf(s, "%s\n", _vm->_char.getFullName()); f->writeString(s); sprintf(s, "%s\n", _saveData1); f->writeString(s); - sprintf(s, "%d\n", _char._ani->getX()); + sprintf(s, "%d\n", _vm->_char._ani->getX()); f->writeString(s); - sprintf(s, "%d\n", _char._ani->getY()); + sprintf(s, "%d\n", _vm->_char._ani->getY()); f->writeString(s); sprintf(s, "%d\n", _score); f->writeString(s); sprintf(s, "%u\n", _globalFlags); f->writeString(s); - sprintf(s, "%d\n", _numLocations); + sprintf(s, "%d\n", _vm->_numLocations); f->writeString(s); - for (uint16 _si = 0; _si < _numLocations; _si++) { - sprintf(s, "%s\n%u\n", _locationNames[_si], _localFlags[_si]); + for (uint16 _si = 0; _si < _vm->_numLocations; _si++) { + sprintf(s, "%s\n%u\n", _vm->_locationNames[_si], _vm->_localFlags[_si]); f->writeString(s); } const InventoryItem *item; for (uint16 _si = 0; _si < 30; _si++) { - item = getInventoryItem(_si); + item = _vm->getInventoryItem(_si); sprintf(s, "%u\n%d\n", item->_id, item->_index); f->writeString(s); } @@ -247,8 +252,9 @@ enum { }; -SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine) - : Dialog("ScummSaveLoad"), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) { + +SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) + : Dialog("ScummSaveLoad"), _list(0), _chooseButton(0), _gfxWidget(0) { // _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR; _backgroundType = GUI::Theme::kDialogBackgroundSpecial; @@ -335,7 +341,7 @@ void SaveLoadChooser::reflowLayout() { Dialog::reflowLayout(); } -int Parallaction_ns::buildSaveFileList(Common::StringList& l) { +int SaveLoad_ns::buildSaveFileList(Common::StringList& l) { char buf[200]; @@ -346,7 +352,7 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) { Common::InSaveFile *f = getInSaveFile(i); if (f) { - f->readLine(buf, 199); + f->readLine_OLD(buf, 199); delete f; count++; @@ -359,9 +365,9 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) { } -int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { +int SaveLoad_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) { - SaveLoadChooser* slc = new SaveLoadChooser(caption, button, this); + SaveLoadChooser* slc = new SaveLoadChooser(caption, button); Common::StringList l; @@ -380,7 +386,7 @@ int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const cha -bool Parallaction_ns::loadGame() { +bool SaveLoad_ns::loadGame() { int _di = selectSaveFile( 0, "Load file", "Load" ); if (_di == -1) { @@ -392,15 +398,15 @@ bool Parallaction_ns::loadGame() { GUI::TimedMessageDialog dialog("Loading game...", 1500); dialog.runModal(); - setArrowCursor(); + _vm->_input->setArrowCursor(); return true; } -bool Parallaction_ns::saveGame() { +bool SaveLoad_ns::saveGame() { - if (!scumm_stricmp(_location._name, "caveau")) { + if (!scumm_stricmp(_vm->_location._name, "caveau")) { return false; } @@ -418,7 +424,7 @@ bool Parallaction_ns::saveGame() { } -void Parallaction_ns::setPartComplete(const Character& character) { +void SaveLoad_ns::setPartComplete(const char *part) { char buf[30]; bool alreadyPresent = false; @@ -426,10 +432,10 @@ void Parallaction_ns::setPartComplete(const Character& character) { Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT); if (inFile) { - inFile->readLine(buf, 29); + inFile->readLine_OLD(buf, 29); delete inFile; - if (strstr(buf, character.getBaseName())) { + if (strstr(buf, part)) { alreadyPresent = true; } } @@ -437,7 +443,7 @@ void Parallaction_ns::setPartComplete(const Character& character) { if (!alreadyPresent) { Common::OutSaveFile *outFile = getOutSaveFile(SPECIAL_SAVESLOT); outFile->writeString(buf); - outFile->writeString(character.getBaseName()); + outFile->writeString(part); outFile->finalize(); delete outFile; } @@ -445,17 +451,20 @@ void Parallaction_ns::setPartComplete(const Character& character) { return; } -bool Parallaction_ns::allPartsComplete() { - char buf[30]; +void SaveLoad_ns::getGamePartProgress(bool *complete, int size) { + assert(complete && size >= 3); + char buf[30]; Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT); - inFile->readLine(buf, 29); + inFile->readLine_OLD(buf, 29); delete inFile; - return strstr(buf, "dino") && strstr(buf, "donna") && strstr(buf, "dough"); + complete[0] = strstr(buf, "dino"); + complete[1] = strstr(buf, "donna"); + complete[2] = strstr(buf, "dough"); } -void Parallaction_ns::renameOldSavefiles() { +void SaveLoad_ns::renameOldSavefiles() { bool exists[NUM_SAVESLOTS]; uint num = 0; @@ -463,7 +472,7 @@ void Parallaction_ns::renameOldSavefiles() { for (i = 0; i < NUM_SAVESLOTS; i++) { exists[i] = false; - Common::String name = genSaveFileName(i, true); + Common::String name = genOldSaveFileName(i); Common::InSaveFile *f = _saveFileMan->openForLoading(name.c_str()); if (f) { exists[i] = true; @@ -491,8 +500,8 @@ void Parallaction_ns::renameOldSavefiles() { uint success = 0; for (i = 0; i < NUM_SAVESLOTS; i++) { if (exists[i]) { - Common::String oldName = genSaveFileName(i, true); - Common::String newName = genSaveFileName(i, false); + Common::String oldName = genOldSaveFileName(i); + Common::String newName = genSaveFileName(i); if (_saveFileMan->renameSavefile(oldName.c_str(), newName.c_str())) { success++; } else { @@ -518,4 +527,28 @@ void Parallaction_ns::renameOldSavefiles() { } +bool SaveLoad_br::loadGame() { + // TODO: implement loadgame + return false; +} + +bool SaveLoad_br::saveGame() { + // TODO: implement savegame + return false; +} + +void SaveLoad_br::getGamePartProgress(bool *complete, int size) { + assert(complete && size >= 3); + + // TODO: implement progress loading + + complete[0] = true; + complete[1] = true; + complete[2] = true; +} + +void SaveLoad_br::setPartComplete(const char *part) { + // TODO: implement progress saving +} + } // namespace Parallaction diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h new file mode 100644 index 0000000000..10bb8aafc2 --- /dev/null +++ b/engines/parallaction/saveload.h @@ -0,0 +1,96 @@ +/* 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. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + + +#ifndef PARALLACTION_SAVELOAD_H +#define PARALLACTION_SAVELOAD_H + +namespace Parallaction { + +struct Character; + + +class SaveLoad { + +protected: + Common::SaveFileManager *_saveFileMan; + Common::String _saveFilePrefix; + + Common::String genSaveFileName(uint slot); + Common::InSaveFile *getInSaveFile(uint slot); + Common::OutSaveFile *getOutSaveFile(uint slot); + +public: + SaveLoad(Common::SaveFileManager* saveFileMan, const char *prefix) : _saveFileMan(saveFileMan), _saveFilePrefix(prefix) { } + virtual ~SaveLoad() { } + + virtual bool loadGame() = 0; + virtual bool saveGame() = 0; + virtual void getGamePartProgress(bool *complete, int size) = 0; + virtual void setPartComplete(const char *part) = 0; + + virtual void renameOldSavefiles() { } +}; + +class SaveLoad_ns : public SaveLoad { + + Parallaction_ns *_vm; + + Common::String _saveFileName; + Common::String genOldSaveFileName(uint slot); + +protected: + void renameOldSavefiles(); + void doLoadGame(uint16 slot); + void doSaveGame(uint16 slot, const char* name); + int buildSaveFileList(Common::StringList& l); + int selectSaveFile(uint16 arg_0, const char* caption, const char* button); + +public: + SaveLoad_ns(Parallaction_ns *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "nippon"), _vm(vm) { } + + virtual bool loadGame(); + virtual bool saveGame(); + virtual void getGamePartProgress(bool *complete, int size); + virtual void setPartComplete(const char *part); +}; + +class SaveLoad_br : public SaveLoad { + + Parallaction_br *_vm; + +public: + SaveLoad_br(Parallaction_br *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "bra"), _vm(vm) { } + + virtual bool loadGame(); + virtual bool saveGame(); + virtual void getGamePartProgress(bool *complete, int size); + virtual void setPartComplete(const char *part); +}; + + +} // namespace Parallaction + +#endif diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp index 2c5cf281dd..071495e8f1 100644 --- a/engines/parallaction/staticres.cpp +++ b/engines/parallaction/staticres.cpp @@ -29,7 +29,7 @@ namespace Parallaction { -byte Parallaction_ns::_resMouseArrow[256] = { +byte Input::_resMouseArrow_NS[256] = { 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, @@ -335,12 +335,6 @@ const Parallaction_br::Callable Parallaction_br::_dosCallables[] = { void Parallaction_ns::initResources() { -// _zoneFlagNamesRes = _zoneFlagNamesRes_ns; -// _zoneTypeNamesRes = _zoneTypeNamesRes_ns; -// _commandsNamesRes = _commandsNamesRes_ns; - _callableNamesRes = _callableNamesRes_ns; -// _instructionNamesRes = _instructionNamesRes_ns; - _callableNames = new Table(ARRAYSIZE(_callableNamesRes_ns), _callableNamesRes_ns); _localFlagNames = new FixedTable(NUM_LOCATIONS, 1); @@ -356,13 +350,6 @@ void Parallaction_ns::initResources() { void Parallaction_br::initResources() { -// _zoneFlagNamesRes = _zoneFlagNamesRes_br; -// _zoneTypeNamesRes = _zoneTypeNamesRes_br; -// _commandsNamesRes = _commandsNamesRes_br; - _callableNamesRes = _callableNamesRes_br; -// _instructionNamesRes = _instructionNamesRes_br; -// _audioCommandsNamesRes = _audioCommandsNamesRes_br; - _callableNames = new Table(ARRAYSIZE(_callableNamesRes_br), _callableNamesRes_br); _localFlagNames = new FixedTable(NUM_LOCATIONS, 2); diff --git a/engines/queen/input.cpp b/engines/queen/input.cpp index 9f03c341c9..84e21fbcaa 100644 --- a/engines/queen/input.cpp +++ b/engines/queen/input.cpp @@ -118,9 +118,10 @@ void Input::delay(uint amount) { case Common::EVENT_RBUTTONDOWN: _mouseButton |= MOUSE_RBUTTON; break; - + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->quitGame(); + if (_cutawayRunning) + _cutawayQuit = true; return; default: diff --git a/engines/queen/journal.cpp b/engines/queen/journal.cpp index 0327fb74b8..7846fa5c36 100644 --- a/engines/queen/journal.cpp +++ b/engines/queen/journal.cpp @@ -84,8 +84,8 @@ void Journal::use() { case Common::EVENT_WHEELDOWN: handleMouseWheel(1); break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->quitGame(); return; default: break; @@ -385,16 +385,18 @@ void Journal::drawPanelText(int y, const char *text) { char s[128]; strncpy(s, text, 127); s[127] = 0; + char *p; + // remove leading and trailing spaces (necessary for spanish version) - for (char *p = s + strlen(s) - 1; p >= s && *p == ' '; --p) { + for (p = s + strlen(s) - 1; p >= s && *p == ' '; --p) { *p = 0; } text = s; - for (char *p = s; *p == ' '; ++p) { + for (p = s; *p == ' '; ++p) { text = p + 1; } // draw the substrings - char *p = (char *)strchr(text, ' '); + p = (char *)strchr(text, ' '); if (!p) { int x = (128 - _vm->display()->textWidth(text)) / 2; _vm->display()->setText(x, y, text, false); diff --git a/engines/queen/logic.cpp b/engines/queen/logic.cpp index 9e4770553c..7fcc761018 100644 --- a/engines/queen/logic.cpp +++ b/engines/queen/logic.cpp @@ -2076,6 +2076,8 @@ bool LogicDemo::changeToSpecialRoom() { displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true); playCutaway("CLOGO.CUT"); sceneReset(); + if (_vm->quit()) + return true; currentRoom(ROOM_HOTEL_LOBBY); entryObj(584); displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true); @@ -2129,7 +2131,11 @@ bool LogicGame::changeToSpecialRoom() { } else if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) { displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true); playCutaway("COPY.CUT"); + if (_vm->quit()) + return true; playCutaway("CLOGO.CUT"); + if (_vm->quit()) + return true; if (_vm->resource()->getPlatform() != Common::kPlatformAmiga) { if (ConfMan.getBool("alt_intro") && _vm->resource()->isCD()) { playCutaway("CINTR.CUT"); @@ -2137,7 +2143,11 @@ bool LogicGame::changeToSpecialRoom() { playCutaway("CDINT.CUT"); } } + if (_vm->quit()) + return true; playCutaway("CRED.CUT"); + if (_vm->quit()) + return true; _vm->display()->palSetPanel(); sceneReset(); currentRoom(ROOM_HOTEL_LOBBY); diff --git a/engines/queen/midiadlib.cpp b/engines/queen/midiadlib.cpp index 155bb66716..200c7282f9 100644 --- a/engines/queen/midiadlib.cpp +++ b/engines/queen/midiadlib.cpp @@ -132,7 +132,7 @@ int AdlibMidiDriver::open() { adlibSetNoteVolume(i, 0); adlibTurnNoteOff(i); } - _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); return 0; } diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index c95e44b477..6cdd020b8f 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -60,9 +60,12 @@ public: virtual const char *getName() const; virtual const char *getCopyright() const; + virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual GameDescriptor findGame(const char *gameid) const; - virtual GameList detectGames(const FSList &fslist) const; + virtual GameList detectGames(const Common::FSList &fslist) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; virtual PluginError createInstance(OSystem *syst, Engine **engine) const; }; @@ -75,6 +78,14 @@ const char *QueenMetaEngine::getCopyright() const { return "Flight of the Amazon Queen (C) John Passfield and Steve Stamatiadis"; } +bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + GameList QueenMetaEngine::getSupportedGames() const { GameList games; games.push_back(queenGameDescriptor); @@ -88,11 +99,11 @@ GameDescriptor QueenMetaEngine::findGame(const char *gameid) const { return GameDescriptor(); } -GameList QueenMetaEngine::detectGames(const FSList &fslist) const { +GameList QueenMetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; // Iterate over all files in the given directory - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (file->isDirectory()) { continue; } @@ -121,6 +132,46 @@ GameList QueenMetaEngine::detectGames(const FSList &fslist) const { return detectedGames; } +SaveStateList QueenMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + char saveDesc[32]; + Common::String pattern = target; + pattern += ".s??"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 2 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 2); + + if (slotNum >= 0 && slotNum <= 99) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + for (int i = 0; i < 4; i++) + in->readUint32BE(); + in->read(saveDesc, 32); + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + delete in; + } + } + } + + return saveList; +} + +void QueenMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".s%02d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + PluginError QueenMetaEngine::createInstance(OSystem *syst, Engine **engine) const { assert(engine); *engine = new Queen::QueenEngine(syst); @@ -180,6 +231,10 @@ void QueenEngine::checkOptionSettings() { } } +void QueenEngine::syncSoundSettings() { + readOptionSettings(); +} + void QueenEngine::readOptionSettings() { _sound->setVolume(ConfMan.getInt("music_volume")); _sound->musicToggle(!ConfMan.getBool("music_mute")); @@ -381,8 +436,8 @@ int QueenEngine::go() { loadGameState(ConfMan.getInt("save_slot")); } _lastSaveTime = _lastUpdateTime = _system->getMillis(); - _quit = false; - while (!_quit) { + + while (!quit()) { if (_logic->newRoom() > 0) { _logic->update(); _logic->oldRoom(_logic->currentRoom()); @@ -428,10 +483,6 @@ int QueenEngine::init() { _logic = new LogicGame(this); } - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - // Set mixer music volume to maximum, since music volume is regulated by MusicPlayer's MIDI messages - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); - _sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression()); _walk = new Walk(this); //_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0; diff --git a/engines/queen/queen.h b/engines/queen/queen.h index 1eea43e882..66931e037d 100644 --- a/engines/queen/queen.h +++ b/engines/queen/queen.h @@ -97,13 +97,13 @@ public: void checkOptionSettings(); void readOptionSettings(); void writeOptionSettings(); + virtual void syncSoundSettings(); int talkSpeed() const { return _talkSpeed; } void talkSpeed(int speed) { _talkSpeed = speed; } bool subtitles() const { return _subtitles; } void subtitles(bool enable) { _subtitles = enable; } - void quitGame() { _quit = true; } - + void update(bool checkPlayerInput = false); bool canLoadOrSave() const; @@ -137,7 +137,6 @@ protected: int _talkSpeed; bool _subtitles; - bool _quit; uint32 _lastSaveTime; uint32 _lastUpdateTime; diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp index b3bd663baf..38d841e96a 100644 --- a/engines/queen/resource.cpp +++ b/engines/queen/resource.cpp @@ -132,7 +132,7 @@ void Resource::loadTextFile(const char *filename, Common::StringList &stringList seekResourceFile(re->bundle, re->offset); char buf[512]; Common::SeekableSubReadStream stream(&_resourceFile, re->offset, re->offset + re->size); - while (stream.readLine(buf, 512)) { + while (stream.readLine_OLD(buf, 512)) { stringList.push_back(buf); } } diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index 27cf1bf6a2..ccaac8227d 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -54,10 +54,27 @@ namespace Queen { class AudioStreamWrapper : public Audio::AudioStream { protected: Audio::AudioStream *_stream; + int _rate; public: AudioStreamWrapper(Audio::AudioStream *stream) { _stream = stream; + + int rate = _stream->getRate(); + + // A file where the sample rate claims to be 11025 Hz is + // probably compressed with the old tool. We force the real + // sample rate, which is 11840 Hz. + // + // However, a file compressed with the newer tool is not + // guaranteed to have a sample rate of 11840 Hz. LAME will + // automatically resample it to 12000 Hz. So in all other + // cases, we use the rate from the file. + + if (rate == 11025) + _rate = 11840; + else + _rate = rate; } ~AudioStreamWrapper() { delete _stream; @@ -75,7 +92,7 @@ public: return _stream->endOfStream(); } int getRate() const { - return 11840; + return _rate; } int32 getTotalPlayTime() { return _stream->getTotalPlayTime(); @@ -261,8 +278,6 @@ void PCSound::playSpeech(const char *base) { void PCSound::setVolume(int vol) { Sound::setVolume(vol); - // Set mixer music volume to maximum, since music volume is regulated by MusicPlayer's MIDI messages - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); _music->setVolume(vol); } @@ -316,7 +331,8 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so if (sound) { f->read(sound, size); byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11840, flags); + Audio::Mixer::SoundType type = (soundHandle == &_speechHandle) ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType; + _mixer->playRaw(type, soundHandle, sound, size, 11840, flags); } } diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp index ff18ef37d1..fa2ca669cd 100644 --- a/engines/queen/talk.cpp +++ b/engines/queen/talk.cpp @@ -807,7 +807,7 @@ void Talk::speakSegment( switch (command) { case SPEAK_PAUSE: - for (i = 0; i < 10 && !_vm->input()->talkQuit(); i++) { + for (i = 0; i < 10 && !_vm->input()->talkQuit() && !_vm->quit(); i++) { _vm->update(); } return; diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index 9fffb0f8bf..e9e146013f 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -866,7 +866,7 @@ int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) { readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE - while (!readS.eos()) { + while (readS.pos() != readS.size()) { if (reallyFill) { anim->frameOffsets[currentFrame] = readS.pos(); diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp index 9c897d8ebc..a31e9b755a 100644 --- a/engines/saga/detection.cpp +++ b/engines/saga/detection.cpp @@ -147,9 +147,20 @@ public: return "Inherit the Earth (C) Wyrmkeep Entertainment"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; }; +bool SagaMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Saga::SAGAGameDescription *gd = (const Saga::SAGAGameDescription *)desc; if (gd) { @@ -158,6 +169,46 @@ bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common return gd != 0; } +SaveStateList SagaMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + char saveDesc[SAVE_TITLE_SIZE]; + Common::String pattern = target; + pattern += ".s??"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 2 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 2); + + if (slotNum >= 0 && slotNum <= 99) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + for (int i = 0; i < 3; i++) + in->readUint32BE(); + in->read(saveDesc, SAVE_TITLE_SIZE); + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); + delete in; + } + } + } + + return saveList; +} + +void SagaMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".s%02d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + #if PLUGIN_ENABLED_DYNAMIC(SAGA) REGISTER_PLUGIN_DYNAMIC(SAGA, PLUGIN_TYPE_ENGINE, SagaMetaEngine); #else diff --git a/engines/saga/input.cpp b/engines/saga/input.cpp index ac80d87dd0..61b729b701 100644 --- a/engines/saga/input.cpp +++ b/engines/saga/input.cpp @@ -141,9 +141,6 @@ int SagaEngine::processInput() { break; case Common::EVENT_MOUSEMOVE: break; - case Common::EVENT_QUIT: - shutDown(); - break; default: break; } diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 256e231f57..abf8094533 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -688,7 +688,7 @@ bool Interface::processAscii(Common::KeyState keystate) { setMode(kPanelMain); _vm->_script->setNoPendingVerb(); } else if (ascii == 'q' || ascii == 'Q') { - _vm->shutDown(); + _vm->quitGame(); } break; case kPanelBoss: @@ -1084,7 +1084,7 @@ void Interface::setQuit(PanelButton *panelButton) { if (_vm->getGameId() == GID_IHNM_DEMO) _vm->_scene->creditsScene(); // display sales info for IHNM demo else - _vm->shutDown(); + _vm->quitGame(); break; } } @@ -1153,6 +1153,7 @@ void Interface::setLoad(PanelButton *panelButton) { debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber); setMode(kPanelMain); _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber)); + _vm->syncSoundSettings(); } } } @@ -1616,6 +1617,7 @@ void Interface::setOption(PanelButton *panelButton) { debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber); setMode(kPanelMain); _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber)); + _vm->syncSoundSettings(); } } } else { @@ -1644,14 +1646,16 @@ void Interface::setOption(PanelButton *panelButton) { } break; case kTextMusic: - _vm->_musicVolume = (_vm->_musicVolume + 1) % 11; - _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); - ConfMan.setInt("music_volume", _vm->_musicVolume * 25); + _vm->_musicVolume = _vm->_musicVolume + 25; + if (_vm->_musicVolume > 255) _vm->_musicVolume = 0; + _vm->_music->setVolume(_vm->_musicVolume, 1); + ConfMan.setInt("music_volume", _vm->_musicVolume); break; case kTextSound: - _vm->_soundVolume = (_vm->_soundVolume + 1) % 11; - _vm->_sound->setVolume(_vm->_soundVolume == 10 ? 255 : _vm->_soundVolume * 25); - ConfMan.setInt("sfx_volume", _vm->_soundVolume * 25); + _vm->_soundVolume = _vm->_soundVolume + 25; + if (_vm->_soundVolume > 255) _vm->_soundVolume = 0; + ConfMan.setInt("sound_volume", _vm->_soundVolume); + _vm->_sound->setVolume(); break; case kTextVoices: if (_vm->_voiceFilesExist) { @@ -1669,6 +1673,11 @@ void Interface::setOption(PanelButton *panelButton) { _vm->_subtitlesEnabled = true; // Set it to "Text" _vm->_voicesEnabled = false; } + + _vm->_speechVolume = _vm->_speechVolume + 25; + if (_vm->_speechVolume > 255) _vm->_speechVolume = 0; + ConfMan.setInt("speech_volume", _vm->_speechVolume); + _vm->_sound->setVolume(); ConfMan.setBool("subtitles", _vm->_subtitlesEnabled); ConfMan.setBool("voices", _vm->_voicesEnabled); @@ -2269,13 +2278,13 @@ void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelBut break; case kTextMusic: if (_vm->_musicVolume) - textId = kText10Percent + _vm->_musicVolume - 1; + textId = kText10Percent + _vm->_musicVolume / 25 - 1; else textId = kTextOff; break; case kTextSound: if (_vm->_soundVolume) - textId = kText10Percent + _vm->_soundVolume - 1; + textId = kText10Percent + _vm->_soundVolume / 25 - 1; else textId = kTextOff; break; diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp index 6614f4098f..aaa428ca53 100644 --- a/engines/saga/introproc_ihnm.cpp +++ b/engines/saga/introproc_ihnm.cpp @@ -59,8 +59,12 @@ int Scene::IHNMStartProc() { // Play Cyberdreams logo for 168 frames if (!playTitle(0, logoLength, true)) { + if (_vm->quit()) + return !SUCCESS; // Play Dreamers Guild logo for 10 seconds if (!playLoopingTitle(1, 10)) { + if (_vm->quit()) + return !SUCCESS; // Play the title music _vm->_music->play(1, MUSIC_NORMAL); // Play title screen @@ -70,6 +74,8 @@ int Scene::IHNMStartProc() { } else { _vm->_music->play(1, MUSIC_NORMAL); playTitle(0, 10); + if (_vm->quit()) + return !SUCCESS; playTitle(2, 12); } @@ -142,9 +148,9 @@ bool Scene::checkKey() { while (_vm->_eventMan->pollEvent(event)) { switch (event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: res = true; - _vm->shutDown(); break; case Common::EVENT_KEYDOWN: // Don't react to modifier keys alone. The original did @@ -187,7 +193,7 @@ bool Scene::playTitle(int title, int time, int mode) { _vm->_gfx->getCurrentPal(pal_cut); - while (!done) { + while (!done && !_vm->quit()) { curTime = _vm->_system->getMillis(); switch (phase) { diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 732bd0b50c..5bf0c0ec03 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -249,6 +249,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); @@ -346,7 +348,7 @@ void MusicPlayer::stopMusic() { } } -Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled) : _vm(vm), _mixer(mixer), _enabled(enabled), _adlib(false) { +Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), _mixer(mixer), _adlib(false) { _player = new MusicPlayer(driver); _currentVolume = 0; @@ -402,7 +404,7 @@ void Music::musicVolumeGauge() { } void Music::setVolume(int volume, int time) { - _targetVolume = volume * 2; // ScummVM has different volume scale + _targetVolume = volume; _currentVolumePercent = 0; if (volume == -1) // Set Full volume @@ -432,11 +434,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { uint32 loopStart; debug(2, "Music::play %d, %d", resourceId, flags); - - if (!_enabled) { - return; - } - + if (isPlaying() && _trackNumber == resourceId) { return; } @@ -444,11 +442,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { _trackNumber = resourceId; _player->stopMusic(); _mixer->stopHandle(_musicHandle); - - if (!_vm->_musicVolume) { - return; - } - + int realTrackNumber; if (_vm->getGameType() == GType_ITE) { @@ -591,7 +585,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) { parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); _player->_parser = parser; - setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); + setVolume(_vm->_musicVolume); if (flags & MUSIC_LOOP) _player->setLoop(true); @@ -609,7 +603,7 @@ void Music::pause(void) { } void Music::resume(void) { - _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); + _player->setVolume(_vm->_musicVolume); _player->setPlaying(true); } diff --git a/engines/saga/music.h b/engines/saga/music.h index 1953dc6f91..57ff9e0671 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -105,7 +105,7 @@ protected: class Music { public: - Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled); + Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver); ~Music(void); void setNativeMT32(bool b) { _player->setNativeMT32(b); } bool hasNativeMT32() { return _player->hasNativeMT32(); } @@ -133,7 +133,6 @@ private: Audio::SoundHandle _musicHandle; uint32 _trackNumber; - int _enabled; bool _adlib; int _targetVolume; diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp index e150caeca5..05b1162973 100644 --- a/engines/saga/rscfile.cpp +++ b/engines/saga/rscfile.cpp @@ -121,7 +121,7 @@ bool Resource::loadSagaContext(ResourceContext *context, uint32 contextOffset, u resourceData->offset = contextOffset + readS1.readUint32(); resourceData->size = readS1.readUint32(); //sanity check - if ((resourceData->offset > context->file->size()) || (resourceData->size > contextSize)) { + if ((resourceData->offset > (uint)context->file->size()) || (resourceData->size > contextSize)) { result = false; break; } @@ -181,8 +181,8 @@ bool Resource::loadMacContext(ResourceContext *context) { macDataLength = context->file->readUint32BE(); macMapLength = context->file->readUint32BE(); - if (macDataOffset >= context->file->size() || macMapOffset >= context->file->size() || - macDataLength + macMapLength > context->file->size()) { + if (macDataOffset >= (uint)context->file->size() || macMapOffset >= (uint)context->file->size() || + macDataLength + macMapLength > (uint)context->file->size()) { return false; } @@ -384,24 +384,24 @@ bool Resource::createContexts() { if (!soundFileInArray) { if (_vm->getGameType() == GType_ITE) { // If the sound file is not specified in the detector table, add it here - if (Common::File::exists("sounds.rsc") || Common::File::exists("sounds.cmp")) { + if (Common::File::exists("sounds.rsc")) { _contextsCount++; soundFileIndex = _contextsCount - 1; - if (Common::File::exists("sounds.rsc")) { - sprintf(soundFileName, "sounds.rsc"); - } else { - sprintf(soundFileName, "sounds.cmp"); - _vm->_gf_compressed_sounds = true; - } - } else if (Common::File::exists("soundsd.rsc") || Common::File::exists("soundsd.cmp")) { + sprintf(soundFileName, "sounds.rsc"); + } else if (Common::File::exists("sounds.cmp")) { _contextsCount++; soundFileIndex = _contextsCount - 1; - if (Common::File::exists("soundsd.rsc")) { - sprintf(soundFileName, "soundsd.rsc"); - } else { - sprintf(soundFileName, "soundsd.cmp"); - _vm->_gf_compressed_sounds = true; - } + sprintf(soundFileName, "sounds.cmp"); + _vm->_gf_compressed_sounds = true; + } else if (Common::File::exists("soundsd.rsc")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + sprintf(soundFileName, "soundsd.rsc"); + } else if (Common::File::exists("soundsd.cmp")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + sprintf(soundFileName, "soundsd.cmp"); + _vm->_gf_compressed_sounds = true; } else { // No sound file found, don't add any file to the array soundFileInArray = true; @@ -410,15 +410,15 @@ bool Resource::createContexts() { } } else { // If the sound file is not specified in the detector table, add it here - if (Common::File::exists("sfx.res") || Common::File::exists("sfx.cmp")) { + if (Common::File::exists("sfx.res")) { _contextsCount++; soundFileIndex = _contextsCount - 1; - if (Common::File::exists("sfx.res")) { - sprintf(soundFileName, "sfx.res"); - } else { - sprintf(soundFileName, "sfx.cmp"); - _vm->_gf_compressed_sounds = true; - } + sprintf(soundFileName, "sfx.res"); + } else if (Common::File::exists("sfx.cmp")) { + _contextsCount++; + soundFileIndex = _contextsCount - 1; + sprintf(soundFileName, "sfx.cmp"); + _vm->_gf_compressed_sounds = true; } else { // No sound file found, don't add any file to the array soundFileInArray = true; @@ -429,24 +429,24 @@ bool Resource::createContexts() { if (!voicesFileInArray) { if (_vm->getGameType() == GType_ITE) { // If the voices file is not specified in the detector table, add it here - if (Common::File::exists("voices.rsc") || Common::File::exists("voices.cmp")) { + if (Common::File::exists("voices.rsc")) { _contextsCount++; voicesFileIndex = _contextsCount - 1; - if (Common::File::exists("voices.rsc")) { - sprintf(_voicesFileName[0], "voices.rsc"); - } else { - sprintf(_voicesFileName[0], "voices.cmp"); - _vm->_gf_compressed_sounds = true; - } - } else if (Common::File::exists("voicesd.rsc") || Common::File::exists("voicesd.cmp")) { + sprintf(_voicesFileName[0], "voices.rsc"); + } else if (Common::File::exists("voices.cmp")) { _contextsCount++; voicesFileIndex = _contextsCount - 1; - if (Common::File::exists("voicesd.rsc")) { - sprintf(_voicesFileName[0], "voicesd.rsc"); - } else { - sprintf(_voicesFileName[0], "voicesd.cmp"); - _vm->_gf_compressed_sounds = true; - } + sprintf(_voicesFileName[0], "voices.cmp"); + _vm->_gf_compressed_sounds = true; + } else if (Common::File::exists("voicesd.rsc")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + sprintf(_voicesFileName[0], "voicesd.rsc"); + } else if (Common::File::exists("voicesd.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + sprintf(_voicesFileName[0], "voicesd.cmp"); + _vm->_gf_compressed_sounds = true; } else if (Common::File::exists("inherit the earth voices") || Common::File::exists("inherit the earth voices.cmp")) { _contextsCount++; @@ -493,15 +493,15 @@ bool Resource::createContexts() { sprintf(_voicesFileName[0], "voicess.cmp"); _vm->_gf_compressed_sounds = true; } - } else if (Common::File::exists("voicesd.res") || Common::File::exists("voicesd.cmp")) { + } else if (Common::File::exists("voicesd.res")) { _contextsCount++; voicesFileIndex = _contextsCount - 1; - if (Common::File::exists("voicesd.res")) { - sprintf(_voicesFileName[0], "voicesd.res"); - } else { - sprintf(_voicesFileName[0], "voicesd.cmp"); - _vm->_gf_compressed_sounds = true; - } + sprintf(_voicesFileName[0], "voicesd.res"); + } else if (Common::File::exists("voicesd.cmp")) { + _contextsCount++; + voicesFileIndex = _contextsCount - 1; + sprintf(_voicesFileName[0], "voicesd.cmp"); + _vm->_gf_compressed_sounds = true; } else { // No voice file found, don't add any file to the array voicesFileInArray = true; @@ -521,20 +521,22 @@ bool Resource::createContexts() { if (_vm->getGameType() == GType_ITE) { // Check for digital music in ITE - if (Common::File::exists("music.rsc") || Common::File::exists("music.cmp")) { + if (Common::File::exists("music.rsc")) { _contextsCount++; digitalMusic = true; - if (Common::File::exists("music.cmp")) - sprintf(musicFileName, "music.cmp"); - else - sprintf(musicFileName, "music.rsc"); - } else if (Common::File::exists("musicd.rsc") || Common::File::exists("musicd.cmp")) { + sprintf(musicFileName, "music.rsc"); + } else if (Common::File::exists("music.cmp")) { _contextsCount++; digitalMusic = true; - if (Common::File::exists("musicd.cmp")) - sprintf(musicFileName, "musicd.cmp"); - else - sprintf(musicFileName, "musicd.rsc"); + sprintf(musicFileName, "music.cmp"); + } else if (Common::File::exists("musicd.rsc")) { + _contextsCount++; + digitalMusic = true; + sprintf(musicFileName, "musicd.rsc"); + } else if (Common::File::exists("musicd.cmp")) { + _contextsCount++; + digitalMusic = true; + sprintf(musicFileName, "musicd.cmp"); } else { digitalMusic = false; } @@ -661,9 +663,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { if (chapter < 0) chapter = (_vm->getGameId() != GID_IHNM_DEMO) ? 8 : 7; - // TODO - //if (module.voiceLUT) - // free module.voiceLUT; + _vm->_script->_globalVoiceLUT.freeMem(); // TODO: close chapter context, or rather reassign it in our case @@ -769,7 +769,6 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { _vm->_sprite->_mainSprites.freeMem(); _vm->_sprite->loadList(_metaResource.mainSpritesID, _vm->_sprite->_mainSprites); - _vm->_actor->loadObjList(_metaResource.objectCount, _metaResource.objectsResourceID); _vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourcePointer, resourceLength); @@ -805,49 +804,21 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) { free(resourcePointer); } else { // The IHNM demo has a fixed music track and doesn't load a song table - _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); + _vm->_music->setVolume(_vm->_musicVolume, 1); _vm->_music->play(3, MUSIC_LOOP); free(resourcePointer); } int voiceLUTResourceID = 0; - _vm->_script->_globalVoiceLUT.freeMem(); - - switch (chapter) { - case 1: - _vm->_sndRes->setVoiceBank(1); - voiceLUTResourceID = 23; - break; - case 2: - _vm->_sndRes->setVoiceBank(2); - voiceLUTResourceID = 24; - break; - case 3: - _vm->_sndRes->setVoiceBank(3); - voiceLUTResourceID = 25; - break; - case 4: - _vm->_sndRes->setVoiceBank(4); - voiceLUTResourceID = 26; - break; - case 5: - _vm->_sndRes->setVoiceBank(5); - voiceLUTResourceID = 27; - break; - case 6: - _vm->_sndRes->setVoiceBank(6); - voiceLUTResourceID = 28; - break; - case 7: + if (chapter != 7) { + int voiceBank = (chapter == 8) ? 0 : chapter; + _vm->_sndRes->setVoiceBank(voiceBank); + voiceLUTResourceID = 22 + voiceBank; + } else { // IHNM demo _vm->_sndRes->setVoiceBank(0); voiceLUTResourceID = 17; - break; - case 8: - _vm->_sndRes->setVoiceBank(0); - voiceLUTResourceID = 22; - break; } if (voiceLUTResourceID) { diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index fafbd02cec..5ce5d6ab93 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -64,7 +64,6 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) _leftMouseButtonPressed = _rightMouseButtonPressed = false; _console = NULL; - _quit = false; _resource = NULL; _sndRes = NULL; @@ -93,20 +92,20 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc) // The Linux version of Inherit the Earth puts all data files in an // 'itedata' sub-directory, except for voices.rsc - Common::File::addDefaultDirectory(_gameDataPath + "itedata/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("itedata")); // The Windows version of Inherit the Earth puts various data files in // other subdirectories. - Common::File::addDefaultDirectory(_gameDataPath + "graphics/"); - Common::File::addDefaultDirectory(_gameDataPath + "music/"); - Common::File::addDefaultDirectory(_gameDataPath + "sound/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("graphics")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("music")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("sound")); // The Multi-OS version puts the voices file in the root directory of // the CD. The rest of the data files are in game/itedata - Common::File::addDefaultDirectory(_gameDataPath + "game/itedata/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("game").getChild("itedata")); // Mac CD Wyrmkeep - Common::File::addDefaultDirectory(_gameDataPath + "patch/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("patch")); _displayClip.left = _displayClip.top = 0; syst->getEventManager()->registerRandomSource(_rnd, "saga"); @@ -142,8 +141,7 @@ SagaEngine::~SagaEngine() { } int SagaEngine::init() { - _soundVolume = ConfMan.getInt("sfx_volume") / 25; - _musicVolume = ConfMan.getInt("music_volume") / 25; + _musicVolume = ConfMan.getInt("music_volume"); _subtitlesEnabled = ConfMan.getBool("subtitles"); _readingSpeed = getTalkspeed(); _copyProtection = ConfMan.getBool("copy_protection"); @@ -194,29 +192,21 @@ int SagaEngine::init() { if (native_mt32) _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - _music = new Music(this, _mixer, _driver, _musicVolume); + _music = new Music(this, _mixer, _driver); _music->setNativeMT32(native_mt32); _music->setAdlib(adlib); - - if (!_musicVolume) { - debug(1, "Music disabled."); - } - _render = new Render(this, _system); if (!_render->initialized()) { return FAILURE; } // Initialize system specific sound - _sound = new Sound(this, _mixer, _soundVolume); - if (!_soundVolume) { - debug(1, "Sound disabled."); - } - + _sound = new Sound(this, _mixer); + _interface->converseInit(); _script->setVerb(_script->getVerbType(kVerbWalkTo)); - _music->setVolume(-1, 1); + _music->setVolume(_musicVolume, 1); _gfx->initPalette(); @@ -233,6 +223,8 @@ int SagaEngine::init() { } } + syncSoundSettings(); + // FIXME: This is the ugly way of reducing redraw overhead. It works // well for 320x200 but it's unclear how well it will work for // 640x480. @@ -255,14 +247,22 @@ int SagaEngine::go() { _interface->addToInventory(_actor->objIndexToId(0)); // Magic hat _scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade); } else if (ConfMan.hasKey("save_slot")) { + // Init the current chapter to 8 (character selection) for IHNM + if (getGameType() == GType_IHNM) + _scene->changeScene(-2, 0, kTransitionFade, 8); + // First scene sets up palette _scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade); _events->handleEvents(0); // Process immediate events - _interface->setMode(kPanelMain); - char *fileName; - fileName = calcSaveFileName(ConfMan.getInt("save_slot")); + if (getGameType() != GType_IHNM) + _interface->setMode(kPanelMain); + else + _interface->setMode(kPanelChapterSelection); + + char *fileName = calcSaveFileName(ConfMan.getInt("save_slot")); load(fileName); + syncSoundSettings(); } else { _framesEsc = 0; _scene->startScene(); @@ -270,7 +270,7 @@ int SagaEngine::go() { uint32 currentTicks; - while (!_quit) { + while (!quit()) { if (_console->isAttached()) _console->onFrame(); @@ -520,4 +520,16 @@ int SagaEngine::getTalkspeed() { return (ConfMan.getInt("talkspeed") * 3 + 255 / 2) / 255; } +void SagaEngine::syncSoundSettings() { + _subtitlesEnabled = ConfMan.getBool("subtitles"); + _readingSpeed = getTalkspeed(); + + if (_readingSpeed > 3) + _readingSpeed = 0; + + _musicVolume = ConfMan.getInt("music_volume"); + _music->setVolume(_musicVolume, 1); + _sound->setVolume(); +} + } // End of namespace Saga diff --git a/engines/saga/saga.h b/engines/saga/saga.h index eeb8f7a61b..0b6b3b1478 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -492,7 +492,6 @@ protected: public: SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc); virtual ~SagaEngine(); - void shutDown() { _quit = true; } void save(const char *fileName, const char *saveName); void load(const char *fileName); @@ -513,6 +512,8 @@ public: return isSaveListFull() ? _saveFilesCount : _saveFilesCount + 1; } + virtual void syncSoundSettings(); + int16 _framesEsc; uint32 _globalFlags; @@ -521,6 +522,7 @@ public: int _soundVolume; int _musicVolume; + int _speechVolume; bool _subtitlesEnabled; bool _voicesEnabled; bool _voiceFilesExist; @@ -611,8 +613,6 @@ public: bool _rightMouseButtonPressed; int _mouseClickCount; - bool _quit; - //current game description int _gameNumber; const SAGAGameDescription *_gameDescription; diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index c3c1587822..074b4c933a 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -315,7 +315,7 @@ void Scene::creditsScene() { break; } - _vm->shutDown(); + _vm->quitGame(); return; } diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index ea61f5ce04..e19fd5ae02 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -276,31 +276,14 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) { if (obj->_sceneNumber != ITE_SCENE_INV) { obj->_sceneNumber = ITE_SCENE_INV; - // WORKAROUND for a problematic object in IHNM - // There are 3 different scenes in front of the zeppelin, in Gorrister's chapter. A scene where the - // zeppelin is in the air (scene 17), a scene where it approaches Gorrister's (scene 16) and another one - // where it has landed (scene 18). - // In two of these scenes (the "on air" and "approaching" ones), when the player uses the knife with the - // rope, the associated script picks up object id 16392. In the "zeppelin landed" scene (scene 18), the - // associated script picks up object id 16390. This seems to be a script bug, as it should be id 16392, - // like in the other two scenes, as it is the same object (the rope). Picking up object 16390 leads to an - // assertion anyway, therefore we change the problematic object (16390) to the correct one (16392) here. - // Fixes bug #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" - if (_vm->getGameType() == GType_IHNM) { - if (_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 18) { - if (objectId == 16390) - objectId = 16392; - } - } - - // WORKAROUND for two incorrect object sprites in the IHNM demo - // (the mirror and the icon in Ted's part). Set them correctly here - if (_vm->getGameId() == GID_IHNM_DEMO) { - if (objectId == 16408) - obj->_spriteListResourceId = 24; - if (objectId == 16409) - obj->_spriteListResourceId = 25; - } + // Normally, when objects are picked up, they should always have the same + // _spriteListResourceId as their _index value. Some don't in IHNM, so + // we fix their sprite here + // Fixes bugs #2057200 - "IHNM: Invisible inventory objects", + // #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring" + // and some incorrect objects in the IHNM demo + if (_vm->getGameType() == GType_IHNM) + obj->_spriteListResourceId = obj->_index; _vm->_interface->addToInventory(objectId); } @@ -356,7 +339,7 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) { // exit the game. Known non-interactive demos are GID_ITE_MACDEMO1 and // GID_ITE_WINDEMO1 if (_vm->getFeatures() & GF_NON_INTERACTIVE) - _vm->shutDown(); + _vm->quitGame(); } // Script function #6 (0x06) blocking @@ -572,7 +555,7 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { } if (_vm->getGameType() == GType_ITE && sceneNumber < 0) { - _vm->shutDown(); + _vm->quitGame(); return; } @@ -1482,7 +1465,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) { int16 param = thread->pop() + 9; if (param >= 9 && param <= 34) { - _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); + _vm->_music->setVolume(_vm->_musicVolume, 1); _vm->_music->play(param); } else { _vm->_music->stop(); @@ -1499,7 +1482,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) { if (param1 >= _vm->_music->_songTableLen) { warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1); } else { - _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); + _vm->_music->setVolume(_vm->_musicVolume, 1); _vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL); if (!_vm->_scene->haveChapterPointsChanged()) { _vm->_scene->setCurrentMusicTrack(param1); @@ -1945,7 +1928,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { if (param1 >= _vm->_music->_songTableLen) { warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1); } else { - _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1); + _vm->_music->setVolume(_vm->_musicVolume, 1); event.type = kEvTOneshot; event.code = kMusicEvent; event.param = _vm->_music->_songTable[param1]; diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index 8d269fb3e8..b990b8ddf7 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -169,7 +169,6 @@ void SndRes::playVoice(uint32 resourceId) { } bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) { - byte *soundResource; Audio::AudioStream *voxStream; size_t soundResourceLength; bool result = false; @@ -180,13 +179,13 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff byte flags; size_t voxSize; const GameSoundInfo *soundInfo; + Common::File* file; if (resourceId == (uint32)-1) { return false; } if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) { - Common::File soundFile; char soundFileName[40]; int dirIndex = resourceId / 64; @@ -199,15 +198,23 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } else { sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId); } - soundFile.open(soundFileName); - soundResourceLength = soundFile.size(); - soundResource = new byte[soundResourceLength]; - soundFile.read(soundResource, soundResourceLength); - soundFile.close(); + + file = new Common::File(); + + file->open(soundFileName); + soundResourceLength = file->size(); } else { - _vm->_resource->loadResource(context, resourceId, soundResource, soundResourceLength); + + ResourceData* resourceData = _vm->_resource->getResourceData(context, resourceId); + file = context->getFile(resourceData); + + file->seek(resourceData->offset); + soundResourceLength = resourceData->size; + } + Common::SeekableReadStream& readS = *file; + if ((context->fileType & GAME_VOICEFILE) != 0) { soundInfo = _vm->getVoiceInfo(); } else { @@ -220,16 +227,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff context->table[resourceId].fillSoundPatch(soundInfo); } - MemoryReadStream readS(soundResource, soundResourceLength); resourceType = soundInfo->resourceType; if (soundResourceLength >= 8) { - if (!memcmp(soundResource, "Creative", 8)) { + byte header[8]; + + readS.read(&header, 8); + readS.seek(readS.pos() - 8); + + if (!memcmp(header, "Creative", 8)) { resourceType = kSoundVOC; - } else if (!memcmp(soundResource, "RIFF", 4) != 0) { + } else if (!memcmp(header, "RIFF", 4) != 0) { resourceType = kSoundWAV; - } else if (!memcmp(soundResource, "FORM", 4) != 0) { + } else if (!memcmp(header, "FORM", 4) != 0) { resourceType = kSoundAIFF; } @@ -244,11 +255,11 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff uncompressedSound = true; if ((_vm->getFeatures() & GF_COMPRESSED_SOUNDS) && !uncompressedSound) { - if (soundResource[0] == char(0)) { + if (header[0] == char(0)) { resourceType = kSoundMP3; - } else if (soundResource[0] == char(1)) { + } else if (header[0] == char(1)) { resourceType = kSoundOGG; - } else if (soundResource[0] == char(2)) { + } else if (header[0] == char(2)) { resourceType = kSoundFLAC; } } @@ -268,9 +279,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.stereo = false; if (onlyHeader) { buffer.buffer = NULL; - free(soundResource); } else { - buffer.buffer = soundResource; + buffer.buffer = (byte *) malloc(soundResourceLength); + readS.read(buffer.buffer, soundResourceLength); } result = true; break; @@ -284,9 +295,10 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.buffer = NULL; } else { buffer.buffer = (byte *)malloc(buffer.size); - memcpy(buffer.buffer, soundResource + 36, buffer.size); + + readS.seek(readS.pos() + 36); + readS.read(buffer.buffer, buffer.size); } - free(soundResource); result = true; break; case kSoundVOX: @@ -297,7 +309,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.size = soundResourceLength * 4; if (onlyHeader) { buffer.buffer = NULL; - free(soundResource); } else { voxStream = Audio::makeADPCMStream(&readS, false, soundResourceLength, Audio::kADPCMOki); buffer.buffer = (byte *)malloc(buffer.size); @@ -325,7 +336,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } result = true; } - free(soundResource); break; case kSoundWAV: if (Audio::loadWAVFromStream(readS, size, rate, flags)) { @@ -342,7 +352,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } result = true; } - free(soundResource); break; case kSoundAIFF: if (Audio::loadAIFFFromStream(readS, size, rate, flags)) { @@ -359,7 +368,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } result = true; } - free(soundResource); break; case kSoundMP3: case kSoundOGG: @@ -382,12 +390,17 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff buffer.buffer = NULL; result = true; - free(soundResource); break; default: error("SndRes::load Unknown sound type"); } + + if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) { + delete file; + } + + // In ITE CD De some voices are absent and contain just 5 bytes header // Round it to even number so soundmanager will not crash. // See bug #1256701 diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h index e77c833076..d5507ebc55 100644 --- a/engines/saga/sndres.h +++ b/engines/saga/sndres.h @@ -39,7 +39,6 @@ public: SndRes(SagaEngine *vm); ~SndRes(); - int loadSound(uint32 resourceId); void playSound(uint32 resourceId, int volume, bool loop); void playVoice(uint32 resourceId); int getVoiceLength(uint32 resourceId); diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp index 1d3263d302..1d41d39cf2 100644 --- a/engines/saga/sound.cpp +++ b/engines/saga/sound.cpp @@ -22,8 +22,10 @@ * $Id$ * */ -#include "saga/saga.h" +#include "common/config-manager.h" + +#include "saga/saga.h" #include "saga/sound.h" #include "sound/audiostream.h" @@ -32,13 +34,13 @@ namespace Saga { -Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume) : +Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _voxStream(0) { for (int i = 0; i < SOUND_HANDLES; i++) _handles[i].type = kFreeHandle; - setVolume(volume == 10 ? 255 : volume * 25); + setVolume(); } Sound::~Sound() { @@ -61,7 +63,8 @@ SndHandle *Sound::getHandle() { return NULL; } -void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop) { +void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, + sndHandleType handleType, bool loop) { byte flags; flags = Audio::Mixer::FLAG_AUTOFREE; @@ -81,7 +84,12 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int flags |= Audio::Mixer::FLAG_UNSIGNED; if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) { - _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); + if (handleType == kVoiceHandle) + _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer, + buffer.size, buffer.frequency, flags, -1, volume); + else + _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, + buffer.size, buffer.frequency, flags, -1, volume); } else { Audio::AudioStream *stream = NULL; MemoryReadStream *tmp = NULL; @@ -116,12 +124,23 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int #endif default: // No compression, play it as raw sound - _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); + if (handleType == kVoiceHandle) + _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer, + buffer.size, buffer.frequency, flags, -1, volume); + else + _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, + buffer.size, buffer.frequency, flags, -1, volume); break; } - if (stream != NULL) - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1, volume, 0, true, false); + if (stream != NULL) { + if (handleType == kVoiceHandle) + _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, handle, stream, -1, + volume, 0, true, false); + else + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1, + volume, 0, true, false); + } } } @@ -129,7 +148,7 @@ void Sound::playSound(SoundBuffer &buffer, int volume, bool loop) { SndHandle *handle = getHandle(); handle->type = kEffectHandle; - playSoundBuffer(&handle->handle, buffer, 2 * volume, loop); + playSoundBuffer(&handle->handle, buffer, 2 * volume, handle->type, loop); } void Sound::pauseSound() { @@ -156,7 +175,7 @@ void Sound::playVoice(SoundBuffer &buffer) { SndHandle *handle = getHandle(); handle->type = kVoiceHandle; - playSoundBuffer(&handle->handle, buffer, 255, false); + playSoundBuffer(&handle->handle, buffer, 255, handle->type, false); } void Sound::pauseVoice() { @@ -184,9 +203,11 @@ void Sound::stopAll() { stopSound(); } -void Sound::setVolume(int volume) { - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume); +void Sound::setVolume() { + _vm->_soundVolume = ConfMan.getInt("sound_volume"); + _vm->_speechVolume = ConfMan.getInt("speech_volume"); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _vm->_soundVolume); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _vm->_speechVolume); } } // End of namespace Saga diff --git a/engines/saga/sound.h b/engines/saga/sound.h index ce479c64d1..6d9e42a49d 100644 --- a/engines/saga/sound.h +++ b/engines/saga/sound.h @@ -71,7 +71,7 @@ struct SndHandle { class Sound { public: - Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume); + Sound(SagaEngine *vm, Audio::Mixer *mixer); ~Sound(); void playSound(SoundBuffer &buffer, int volume, bool loop); @@ -86,11 +86,12 @@ public: void stopAll(); - void setVolume(int volume); + void setVolume(); private: - void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop); + void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, + sndHandleType handleType, bool loop); SndHandle *getHandle(); diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp index d9c7b446ba..a1f78e1b9f 100644 --- a/engines/saga/sprite.cpp +++ b/engines/saga/sprite.cpp @@ -412,6 +412,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou while (!readS.eos() && (outPointer < outPointerEnd)) { bg_runcount = readS.readByte(); + if (readS.eos()) + break; fg_runcount = readS.readByte(); for (c = 0; c < bg_runcount && !readS.eos(); c++) { @@ -424,6 +426,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou for (c = 0; c < fg_runcount && !readS.eos(); c++) { *outPointer = readS.readByte(); + if (readS.eos()) + break; if (outPointer < outPointerEnd) outPointer++; else diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index ca5dba7865..d3397fe208 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -177,7 +177,7 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename } struct DetectorDesc { - FilesystemNode node; + Common::FilesystemNode node; Common::String md5; const MD5Table *md5Entry; // Entry of the md5 table corresponding to this file, if any. }; @@ -191,8 +191,8 @@ static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Com // when performing the matching. The first match is returned, so if you // search for "resource" and two nodes "RESOURE and "resource" are present, // the first match is used. -static bool searchFSNode(const FSList &fslist, const Common::String &name, FilesystemNode &result) { - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { +static bool searchFSNode(const Common::FSList &fslist, const Common::String &name, Common::FilesystemNode &result) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (!scumm_stricmp(file->getName().c_str(), name.c_str())) { result = *file; return true; @@ -202,7 +202,7 @@ static bool searchFSNode(const FSList &fslist, const Common::String &name, Files } // The following function tries to detect the language for COMI and DIG -static Common::Language detectLanguage(const FSList &fslist, byte id) { +static Common::Language detectLanguage(const Common::FSList &fslist, byte id) { assert(id == GID_CMI || id == GID_DIG); // Check for LANGUAGE.BND (Dig) resp. LANGUAGE.TAB (CMI). @@ -212,14 +212,14 @@ static Common::Language detectLanguage(const FSList &fslist, byte id) { // switch to MD5 based detection). const char *filename = (id == GID_CMI) ? "LANGUAGE.TAB" : "LANGUAGE.BND"; Common::File tmp; - FilesystemNode langFile; + Common::FilesystemNode langFile; if (!searchFSNode(fslist, filename, langFile) || !tmp.open(langFile)) { // try loading in RESOURCE sub dir... - FilesystemNode resDir; - FSList tmpList; + Common::FilesystemNode resDir; + Common::FSList tmpList; if (searchFSNode(fslist, "RESOURCE", resDir) && resDir.isDirectory() - && resDir.getChildren(tmpList, FilesystemNode::kListFilesOnly) + && resDir.getChildren(tmpList, Common::FilesystemNode::kListFilesOnly) && searchFSNode(tmpList, filename, langFile)) { tmp.open(langFile); } @@ -270,7 +270,7 @@ static Common::Language detectLanguage(const FSList &fslist, byte id) { } -static void computeGameSettingsFromMD5(const FSList &fslist, const GameFilenamePattern *gfp, const MD5Table *md5Entry, DetectorResult &dr) { +static void computeGameSettingsFromMD5(const Common::FSList &fslist, const GameFilenamePattern *gfp, const MD5Table *md5Entry, DetectorResult &dr) { dr.language = md5Entry->language; dr.extra = md5Entry->extra; @@ -315,12 +315,12 @@ static void computeGameSettingsFromMD5(const FSList &fslist, const GameFilenameP } } -static void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) { +static void detectGames(const Common::FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) { DescMap fileMD5Map; DetectorResult dr; char md5str[32+1]; - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (!file->isDirectory()) { DetectorDesc d; d.node = *file; @@ -674,15 +674,30 @@ public: virtual const char *getName() const; virtual const char *getCopyright() const; + virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual GameDescriptor findGame(const char *gameid) const; - virtual GameList detectGames(const FSList &fslist) const; - + virtual GameList detectGames(const Common::FSList &fslist) const; + virtual PluginError createInstance(OSystem *syst, Engine **engine) const; virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; +bool ScummMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave) || + (f == kSupportsMetaInfos) || + (f == kSupportsThumbnails) || + (f == kSupportsSaveDate) || + (f == kSupportsSavePlayTime); +} + GameList ScummMetaEngine::getSupportedGames() const { return GameList(gameDescriptions); } @@ -691,8 +706,7 @@ GameDescriptor ScummMetaEngine::findGame(const char *gameid) const { return Common::AdvancedDetector::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable); } - -GameList ScummMetaEngine::detectGames(const FSList &fslist) const { +GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; Common::List<DetectorResult> results; @@ -769,9 +783,9 @@ PluginError ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) cons } // Fetch the list of files in the current directory - FSList fslist; - FilesystemNode dir(ConfMan.get("path")); - if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) { + Common::FSList fslist; + Common::FilesystemNode dir(ConfMan.get("path")); + if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) { return kInvalidPathError; } @@ -967,6 +981,53 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const { return saveList; } +void ScummMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String filename = ScummEngine::makeSavegameName(target, slot, false); + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + +SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = ScummEngine::makeSavegameName(target, slot, false); + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str()); + + if (!in) + return SaveStateDescriptor(); + + Common::String saveDesc; + Scumm::getSavegameName(in, saveDesc, 0); // FIXME: heversion?!? + delete in; + + // TODO: Cleanup + Graphics::Surface *thumbnail = ScummEngine::loadThumbnailFromSlot(target, slot); + + SaveStateDescriptor desc(slot, saveDesc, filename); + desc.setDeletableFlag(true); + desc.setThumbnail(thumbnail); + + InfoStuff infos; + memset(&infos, 0, sizeof(infos)); + if (ScummEngine::loadInfosFromSlot(target, slot, &infos)) { + int day = (infos.date >> 24) & 0xFF; + int month = (infos.date >> 16) & 0xFF; + int year = infos.date & 0xFFFF; + + desc.setSaveDate(year, month, day); + + int hour = (infos.time >> 8) & 0xFF; + int minutes = infos.time & 0xFF; + + desc.setSaveTime(hour, minutes); + + minutes = infos.playtime / 60; + hour = minutes / 60; + minutes %= 60; + + desc.setPlayTime(hour, minutes); + } + + return desc; +} + #if PLUGIN_ENABLED_DYNAMIC(SCUMM) REGISTER_PLUGIN_DYNAMIC(SCUMM, PLUGIN_TYPE_ENGINE, ScummMetaEngine); #else diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 324cc91e78..d281364a77 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -472,12 +472,14 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "fbear", "fbdemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "fbear", "Fatty Bear Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "fbear", "Fatty Bear", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, + { "fbear", "jfbear", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 }, { "puttmoon", "puttmoon", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttmoon", "moondemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttmoon", "Putt-Putt Moon Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttmoon", "Putt-Putt Moon", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, + { "puttputt", "jputtputt", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 }, { "puttputt", "puttputt", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttputt", "puttdemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "puttputt", "Putt-Putt's Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 8886214910..ee1c0abf1c 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -322,8 +322,6 @@ void SaveLoadChooser::reflowLayout() { if (!g_gui.xmlEval()->getWidgetData("ScummSaveLoad.Thumbnail", x, y, w, h)) error("Error when loading position data for Save/Load Thumbnails."); - _container->resize(x, y, w, h); - int thumbW = kThumbnailWidth; int thumbH = ((g_system->getHeight() % 200 && g_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1); int thumbX = x + (w >> 1) - (thumbW >> 1); @@ -398,8 +396,7 @@ void SaveLoadChooser::updateInfos(bool redraw) { int hours = minutes / 60; minutes %= 60; - snprintf(buffer, 32, "Playtime: %.2d:%.2d", - hours & 0xFF, minutes & 0xFF); + snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours, minutes); _playtime->setLabel(buffer); } else { _date->setLabel("No date saved"); @@ -434,7 +431,7 @@ Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode) { return descriptions; } -MainMenuDialog::MainMenuDialog(ScummEngine *scumm) +ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm) : ScummDialog("ScummMain"), _vm(scumm) { new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P'); @@ -462,7 +459,7 @@ MainMenuDialog::MainMenuDialog(ScummEngine *scumm) _loadDialog = new SaveLoadChooser("Load game:", "Load", false, scumm); } -MainMenuDialog::~MainMenuDialog() { +ScummMenuDialog::~ScummMenuDialog() { delete _aboutDialog; delete _optionsDialog; #ifndef DISABLE_HELP @@ -472,7 +469,7 @@ MainMenuDialog::~MainMenuDialog() { delete _loadDialog; } -void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { case kSaveCmd: save(); @@ -495,7 +492,7 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat break; #endif case kQuitCmd: - _vm->_quit = true; + _vm->quitGame(); close(); break; default: @@ -503,7 +500,7 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat } } -void MainMenuDialog::save() { +void ScummMenuDialog::save() { int idx; _saveDialog->setList(generateSavegameList(_vm, true)); idx = _saveDialog->runModal(); @@ -522,7 +519,7 @@ void MainMenuDialog::save() { } } -void MainMenuDialog::load() { +void ScummMenuDialog::load() { int idx; _loadDialog->setList(generateSavegameList(_vm, false)); idx = _loadDialog->runModal(); diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 0d04d8faea..3837787a3b 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -82,10 +82,10 @@ public: virtual void reflowLayout(); }; -class MainMenuDialog : public ScummDialog { +class ScummMenuDialog : public ScummDialog { public: - MainMenuDialog(ScummEngine *scumm); - ~MainMenuDialog(); + ScummMenuDialog(ScummEngine *scumm); + ~ScummMenuDialog(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); protected: diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index bf13308a0c..f258ddd420 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -42,9 +42,9 @@ void ScummFile::setEnc(byte value) { _encbyte = value; } -void ScummFile::setSubfileRange(uint32 start, uint32 len) { +void ScummFile::setSubfileRange(int32 start, int32 len) { // TODO: Add sanity checks - const uint32 fileSize = File::size(); + const int32 fileSize = File::size(); assert(start <= fileSize); assert(start + len <= fileSize); _subFileStart = start; @@ -125,19 +125,19 @@ bool ScummFile::openSubFile(const Common::String &filename) { } -bool ScummFile::eof() { - return _subFileLen ? (pos() >= _subFileLen) : File::eof(); +bool ScummFile::eos() { + return _subFileLen ? (pos() >= _subFileLen) : File::eos(); // FIXME } -uint32 ScummFile::pos() { +int32 ScummFile::pos() { return File::pos() - _subFileStart; } -uint32 ScummFile::size() { +int32 ScummFile::size() { return _subFileLen ? _subFileLen : File::size(); } -void ScummFile::seek(int32 offs, int whence) { +bool ScummFile::seek(int32 offs, int whence) { if (_subFileLen) { // Constrain the seek to the subfile switch (whence) { @@ -154,7 +154,7 @@ void ScummFile::seek(int32 offs, int whence) { assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen)); whence = SEEK_SET; } - File::seek(offs, whence); + return File::seek(offs, whence); } uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { @@ -162,12 +162,12 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { if (_subFileLen) { // Limit the amount we read by the subfile boundaries. - const uint32 curPos = pos(); + const int32 curPos = pos(); assert(_subFileLen >= curPos); - uint32 newPos = curPos + dataSize; + int32 newPos = curPos + dataSize; if (newPos > _subFileLen) { dataSize = _subFileLen - curPos; - _ioFailed = true; + _myIoFailed = true; } } diff --git a/engines/scumm/file.h b/engines/scumm/file.h index a2695cac59..336f3cde12 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -39,32 +39,37 @@ public: virtual bool open(const Common::String &filename) = 0; virtual bool openSubFile(const Common::String &filename) = 0; - virtual bool eof() = 0; - virtual uint32 pos() = 0; - virtual uint32 size() = 0; - virtual void seek(int32 offs, int whence = SEEK_SET) = 0; + virtual bool eos() = 0; + virtual int32 pos() = 0; + virtual int32 size() = 0; + virtual bool seek(int32 offs, int whence = SEEK_SET) = 0; virtual uint32 read(void *dataPtr, uint32 dataSize) = 0; }; class ScummFile : public BaseScummFile { private: byte _encbyte; - uint32 _subFileStart; - uint32 _subFileLen; + int32 _subFileStart; + int32 _subFileLen; + bool _myIoFailed; + + void setSubfileRange(int32 start, int32 len); + void resetSubfile(); + public: ScummFile(); void setEnc(byte value); - void setSubfileRange(uint32 start, uint32 len); - void resetSubfile(); - bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); - bool eof(); - uint32 pos(); - uint32 size(); - void seek(int32 offs, int whence = SEEK_SET); + bool ioFailed() const { return _myIoFailed || BaseScummFile::ioFailed(); } + void clearIOFailed() { _myIoFailed = false; BaseScummFile::clearIOFailed(); } + + bool eos(); + int32 pos(); + int32 size(); + bool seek(int32 offs, int whence = SEEK_SET); uint32 read(void *dataPtr, uint32 dataSize); }; @@ -106,10 +111,10 @@ public: bool openSubFile(const Common::String &filename); void close(); - bool eof() { return _stream->eos(); } - uint32 pos() { return _stream->pos(); } - uint32 size() { return _stream->size(); } - void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); } + bool eos() { return _stream->eos(); } + int32 pos() { return _stream->pos(); } + int32 size() { return _stream->size(); } + bool seek(int32 offs, int whence = SEEK_SET) { return _stream->seek(offs, whence); } uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } }; diff --git a/engines/scumm/file_nes.cpp b/engines/scumm/file_nes.cpp index 8325436f87..0ddbd0b3ee 100644 --- a/engines/scumm/file_nes.cpp +++ b/engines/scumm/file_nes.cpp @@ -1124,8 +1124,7 @@ bool ScummNESFile::generateResource(int res) { write_byte(&out, 0xD1); write_byte(&out, 0xF5); - if (_stream) - delete _stream; + delete _stream; _stream = new Common::MemoryReadStream(_buf, bufsize); @@ -1221,8 +1220,7 @@ bool ScummNESFile::generateIndex() { for (i = 0; i < (int)sizeof(lfl_index); i++) write_byte(&out, ((byte *)&lfl_index)[i]); - if (_stream) - delete _stream; + delete _stream; _stream = new Common::MemoryReadStream(_buf, bufsize); diff --git a/engines/scumm/file_nes.h b/engines/scumm/file_nes.h index 4d2d6de275..f1a07f8085 100644 --- a/engines/scumm/file_nes.h +++ b/engines/scumm/file_nes.h @@ -68,10 +68,10 @@ public: bool openSubFile(const Common::String &filename); void close(); - bool eof() { return _stream->eos(); } - uint32 pos() { return _stream->pos(); } - uint32 size() { return _stream->size(); } - void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); } + bool eos() { return _stream->eos(); } + int32 pos() { return _stream->pos(); } + int32 size() { return _stream->size(); } + bool seek(int32 offs, int whence = SEEK_SET) { return _stream->seek(offs, whence); } uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } }; diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index d09accafb0..45b078b6f9 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -46,7 +46,7 @@ namespace Scumm { static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); static void fill(byte *dst, int dstPitch, byte color, int w, int h); -#ifndef ARM_USE_GFX_ASM +#ifndef USE_ARM_GFX_ASM static void copy8Col(byte *dst, int dstPitch, const byte *src, int height); #endif static void clear8Col(byte *dst, int dstPitch, int height); @@ -612,32 +612,37 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i assert(0 == (width & 3)); // Compose the text over the game graphics - - // TODO: Optimize this code. There are several things that come immediately to mind: - // (1) Loop unrolling: We could read 4 or even 8 pixels at once, since everything is - // a multiple of 8 here. - // (2) More ASM versions (in particular, the ARM code for the NDS could be used on - // all ARM systems, couldn't it?) - // (3) Better encoding of the text surface data. This is the one with the biggest - // potential. - // (a) Keep an "isEmpty" marker for each pixel row in the _textSurface. The idea - // is that most rows won't contain any text data, so we can just use memcpy. - // (b) RLE encode the _textSurface row-wise. This is an improved variant of (a), - // but also more complicated to implement, and incurs a bigger overhead when - // writing to the text surface. -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, width, _textSurface.pitch); #else - for (int h = 0; h < height * m; ++h) { - for (int w = 0; w < width * m; ++w) { - byte tmp = *text++; - if (tmp == CHARSET_MASK_TRANSPARENCY) - tmp = *src; - *dst++ = tmp; - src++; + // We blit four pixels at a time, for improved performance. + const uint32 *src32 = (const uint32 *)src; + const uint32 *text32 = (const uint32 *)text; + uint32 *dst32 = (uint32 *)dst; + + vsPitch >>= 2; + const int textPitch = (_textSurface.pitch - width * m) >> 2; + for (int h = height * m; h > 0; --h) { + for (int w = width*m; w > 0; w-=4) { + uint32 temp = *text32++; + + // Generate a byte mask for those text pixels (bytes) with + // value CHARSET_MASK_TRANSPARENCY. In the end, each byte + // in mask will be either equal to 0x00 or 0xFF. + // Doing it this way avoids branches and bytewise operations, + // at the cost of readability ;). + uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32; + mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080; + mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080; + + // The following line is equivalent to this code: + // *dst32++ = (*src32++ & mask) | (temp & ~mask); + // However, some compilers can generate somewhat better + // machine code for this equivalent statement: + *dst32++ = ((temp ^ *src32++) & mask) ^ temp; } - src += vsPitch; - text += _textSurface.pitch - width * m; + src32 += vsPitch; + text32 += textPitch; } #endif src = _compositeBuf; @@ -1078,7 +1083,7 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) { } } -#ifdef ARM_USE_GFX_ASM +#ifdef USE_ARM_GFX_ASM #define copy8Col(A,B,C,D) asmCopy8Col(A,B,C,D) @@ -1098,7 +1103,7 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) { } while (--height); } -#endif /* ARM_USE_GFX_ASM */ +#endif /* USE_ARM_GFX_ASM */ static void clear8Col(byte *dst, int dstPitch, int height) { do { diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h index e03fdd1c53..e4c1054450 100644 --- a/engines/scumm/gfx.h +++ b/engines/scumm/gfx.h @@ -174,7 +174,8 @@ struct ColorCycle { struct StripTable; -#define CHARSET_MASK_TRANSPARENCY 253 +#define CHARSET_MASK_TRANSPARENCY 0xFD +#define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD class Gdi { protected: diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s index 83aaa78927..f3a1f20303 100644 --- a/engines/scumm/gfxARM.s +++ b/engines/scumm/gfxARM.s @@ -24,7 +24,7 @@ .global asmDrawStripToScreen .global asmCopy8Col - + @ ARM implementation of asmDrawStripToScreen. @ @ C prototype would be: @@ -47,7 +47,7 @@ asmDrawStripToScreen: @ r2 = text @ r3 = src MOV r12,r13 - STMFD r13!,{r4-r7,r9-r11,R14} + STMFD r13!,{r4-r11,R14} LDMIA r12,{r4,r5,r6,r7} @ r4 = dst @ r5 = vsPitch @@ -69,57 +69,46 @@ asmDrawStripToScreen: MOV r10,#253 ORR r10,r10,r10,LSL #8 ORR r10,r10,r10,LSL #16 @ r10 = mask -yLoop: - MOV r14,r1 @ r14 = width + MOV r8,#0x7F + ORR r8, r8, r8, LSL #8 + ORR r8, r8, r8, LSL #16 @ r8 = 7f7f7f7f + STR r1,[r13,#-4]! @ Stack width + B xLoop + +notEntirelyTransparent: + AND r14,r9, r8 @ r14 = mask & 7f7f7f7f + ADD r14,r14,r8 @ r14 = (mask & 7f7f7f7f)+7f7f7f7f + ORR r14,r14,r9 @ r14 |= mask + BIC r14,r14,r8 @ r14 &= 80808080 + ADD r14,r8, r14,LSR #7 @ r14 = (rx>>7) + 7f7f7f7f + EOR r14,r14,r8 @ r14 ^= 7f7f7f7f + @ So bytes of r14 are 00 where source was matching value,FF otherwise + BIC r11,r11,r14 + AND r12,r12,r14 + ORR r12,r11,r12 + STR r12,[r4],#4 + SUBS r1,r1,#4 + BLE endXLoop xLoop: - LDR r12,[r2],#4 @ r12 = [text] - LDR r11,[r3],#4 @ r11 = [src] - CMP r12,r10 - BNE singleByteCompare - SUBS r14,r14,#4 + LDR r12,[r2],#4 @ r12 = temp = [text] + LDR r11,[r3],#4 @ r11 = [src] + @ Stall + EORS r9, r12,r10 @ r9 = mask = temp ^ TRANSPARENCY + BNE notEntirelyTransparent + SUBS r1, r1, #4 STR r11,[r4], #4 @ r4 = [dst] BGT xLoop - +endXLoop: ADD r2,r2,r7 @ text += textSurfacePitch ADD r3,r3,r5 @ src += vsPitch ADD r4,r4,r6 @ dst += vmScreenWidth SUBS r0,r0,#1 - BGT yLoop - LDMFD r13!,{r4-r7,r9-r11,PC} - -singleByteCompare: - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - MOV r9,r12,LSR #24 @ r9 = 1st byte of [text] - CMP r9,r10,LSR #24 @ if (r9 == mask) - MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src] - ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12 - - STR r12,[r4],#4 - SUBS r14,r14,#4 + LDRGT r1,[r13] @ r14 = width BGT xLoop - - ADD r2,r2,r7 @ text += textSurfacePitch - ADD r3,r3,r5 @ src += vsPitch - ADD r4,r4,r6 @ dst += vmScreenWidth - SUBS r0,r0,#1 - BGT yLoop + ADD r13,r13,#4 end: - LDMFD r13!,{r4-r7,r9-r11,PC} - + LDMFD r13!,{r4-r11,PC} + @ ARM implementation of asmCopy8Col @ @ C prototype would be: @@ -156,4 +145,4 @@ roll2: STR r14,[r0],r1 BNE yLoop2 - LDMFD r13!,{PC} + LDMFD r13!,{PC} diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp index e611c85e9d..685bd00065 100644 --- a/engines/scumm/he/cup_player_he.cpp +++ b/engines/scumm/he/cup_player_he.cpp @@ -99,7 +99,7 @@ void CUP_Player::play() { debug(1, "rate %d width %d height %d", _playbackRate, _width, _height); int ticks = _system->getMillis(); - while (_dataSize != 0 && !_vm->_quit) { + while (_dataSize != 0 && !_vm->quit()) { while (parseNextBlockTag(_fileStream)) { if (_fileStream.ioFailed()) { return; @@ -190,7 +190,7 @@ void CUP_Player::waitForSfxChannel(int channel) { CUP_SfxChannel *sfxChannel = &_sfxChannels[channel]; debug(1, "waitForSfxChannel %d", channel); if ((sfxChannel->flags & kSfxFlagLoop) == 0) { - while (_mixer->isSoundHandleActive(sfxChannel->handle) && !_vm->_quit) { + while (_mixer->isSoundHandleActive(sfxChannel->handle) && !_vm->quit()) { _vm->parseEvents(); _system->delayMillis(10); } @@ -496,7 +496,7 @@ void CUP_Player::handleTOIL(Common::SeekableReadStream &dataStream, uint32 dataS for (int i = 0; i < kSfxChannels; ++i) { waitForSfxChannel(i); } - _vm->_quit = true; + _vm->quitGame(); break; case 7: { int channelSync = dataStream.readUint32LE(); diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index fff8502134..72ba7edb85 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -320,6 +320,8 @@ protected: virtual bool handleNextCharsetCode(Actor *a, int *c); virtual int convertMessageToString(const byte *msg, byte *dst, int dstSize); + void debugInput(byte *string); + /* HE version 72 script opcodes */ void o72_pushDWord(); void o72_getScriptString(); @@ -602,9 +604,12 @@ protected: const OpcodeEntryV100he *_opcodesV100he; + byte _debugInputBuffer[256]; public: ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {} + virtual void resetScumm(); + protected: virtual void setupOpcodes(); virtual void executeOpcode(byte i); @@ -643,6 +648,7 @@ protected: void o100_videoOps(); void o100_wait(); void o100_writeFile(); + void o100_debugInput(); void o100_isResourceLoaded(); void o100_getResourceSize(); void o100_getSpriteGroupInfo(); diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index f72701c229..5717d77640 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -29,6 +29,7 @@ #include "scumm/actor.h" #include "scumm/charset.h" +#include "scumm/dialogs.h" #include "scumm/he/animation_he.h" #include "scumm/he/intern_he.h" #include "scumm/object.h" @@ -256,7 +257,7 @@ void ScummEngine_v100he::setupOpcodes() { OPCODE(o90_cond), OPCODE(o90_cos), /* A8 */ - OPCODE(o6_invalid), + OPCODE(o100_debugInput), OPCODE(o80_getFileSize), OPCODE(o6_getActorFromXY), OPCODE(o72_findAllObjects), @@ -1116,6 +1117,10 @@ void ScummEngine_v100he::o100_resourceRoutines() { _heResId = pop(); break; case 128: + // TODO: Clear Heap + break; + case 129: + // Dummy case break; case 132: if (_heResType == rtScript && _heResId >= _numGlobalScripts) @@ -2136,31 +2141,30 @@ void ScummEngine_v100he::o100_systemOps() { byte string[1024]; byte subOp = fetchScriptByte(); - subOp -= 61; switch (subOp) { - case 0: + case 61: restart(); break; - case 67: + case 128: clearDrawObjectQueue(); break; - case 71: + case 132: // Confirm shutdown - shutDown(); + quitGame(); break; - case 72: - shutDown(); + case 133: + quitGame(); break; - case 73: + case 134: copyScriptString(string, sizeof(string)); debug(0, "Start game (%s)", string); break; - case 74: + case 135: copyScriptString(string, sizeof(string)); debug(0, "Start executable (%s)", string); break; - case 75: + case 136: restoreBackgroundHE(Common::Rect(_screenWidth, _screenHeight)); updatePalette(); break; @@ -2342,6 +2346,30 @@ void ScummEngine_v100he::o100_writeFile() { } } +void ScummEngine_v100he::o100_debugInput() { + byte subOp = fetchScriptByte(); + + switch (subOp) { + case 0: + copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer)); + break; + case 26: + pop(); + break; + case 27: + copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer)); + break; + case 80: + copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer)); + break; + case 92: + debugInput(_debugInputBuffer); + break; + default: + error("o100_debugInput: default case %d", subOp); + } +} + void ScummEngine_v100he::o100_isResourceLoaded() { // Reports percentage of resource loaded by queue int type; @@ -2493,65 +2521,64 @@ void ScummEngine_v100he::o100_getWizData() { int32 x, y; byte subOp = fetchScriptByte(); - subOp -= 20; switch (subOp) { - case 0: + case 20: y = pop(); x = pop(); state = pop(); resId = pop(); push(_wiz->getWizPixelColor(resId, state, x, y, 0)); break; - case 6: + case 26: resId = pop(); push(_wiz->getWizImageStates(resId)); break; - case 13: + case 33: y = pop(); x = pop(); state = pop(); resId = pop(); push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); break; - case 19: + case 39: state = pop(); resId = pop(); _wiz->getWizImageDim(resId, state, w, h); push(h); break; - case 34: + case 54: type = pop(); state = pop(); resId = pop(); push(_wiz->getWizImageData(resId, state, type)); break; - case 64: + case 84: state = pop(); resId = pop(); _wiz->getWizImageDim(resId, state, w, h); push(w); break; - case 65: + case 85: state = pop(); resId = pop(); _wiz->getWizImageSpot(resId, state, x, y); push(x); break; - case 66: + case 86: state = pop(); resId = pop(); _wiz->getWizImageSpot(resId, state, x, y); push(y); break; - case 111: + case 131: pop(); copyScriptString(filename, sizeof(filename)); pop(); push(0); debug(0, "o100_getWizData() case 111 unhandled"); break; - case 112: + case 132: h = pop(); w = pop(); y = pop(); @@ -2896,30 +2923,29 @@ void ScummEngine_v100he::o100_getSpriteInfo() { void ScummEngine_v100he::o100_getVideoData() { // Uses Bink video byte subOp = fetchScriptByte(); - subOp -= 26; switch (subOp) { - case 0: + case 26: pop(); push(_moviePlay->getFrameCount()); break; - case 13: + case 39: pop(); push(_moviePlay->getHeight()); break; - case 14: + case 40: pop(); push(_moviePlay->getImageNum()); break; - case 28: + case 54: debug(0, "o100_getVideoData: subOp 28 stub (%d, %d)", pop(), pop()); push(0); break; - case 47: + case 73: pop(); push(_moviePlay->getCurFrame()); break; - case 58: + case 84: pop(); push(_moviePlay->getWidth()); break; diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp index 3f22c16648..8fcb8b6fe8 100644 --- a/engines/scumm/he/script_v70he.cpp +++ b/engines/scumm/he/script_v70he.cpp @@ -546,6 +546,7 @@ void ScummEngine_v70he::o70_resourceRoutines() { _res->unlock(rtRoomImage, resid); break; case 116: + // TODO: Clear Heap break; case 117: // SO_LOAD_CHARSET resid = pop(); @@ -634,10 +635,10 @@ void ScummEngine_v70he::o70_systemOps() { break; case 160: // Confirm shutdown - shutDown(); + quitGame(); break; case 244: - shutDown(); + quitGame(); break; case 250: id = pop(); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index 6c3d0023d8..7e31383f4e 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -1485,10 +1485,10 @@ void ScummEngine_v72he::o72_systemOps() { break; case 160: // Confirm shutdown - shutDown(); + quitGame(); break; case 244: - shutDown(); + quitGame(); break; case 251: copyScriptString(string, sizeof(string)); @@ -1635,13 +1635,10 @@ void ScummEngine_v72he::o72_drawWizImage() { _wiz->displayWizImage(&wi); } -void ScummEngine_v72he::o72_debugInput() { - byte string[255]; +void ScummEngine_v72he::debugInput(byte* string) { byte *debugInputString; - copyScriptString(string, sizeof(string)); - - DebugInputDialog dialog(this, (char*)string); + DebugInputDialog dialog(this, (char *)string); runDialog(dialog); while (!dialog.done) { parseEvents(); @@ -1654,6 +1651,13 @@ void ScummEngine_v72he::o72_debugInput() { push(readVar(0)); } +void ScummEngine_v72he::o72_debugInput() { + byte string[255]; + + copyScriptString(string, sizeof(string)); + debugInput(string); +} + void ScummEngine_v72he::o72_jumpToScript() { int args[25]; int script; diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index 37ce17c050..6d15303378 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -395,42 +395,41 @@ void ScummEngine_v90he::o90_wizImageOps() { int a, b; int subOp = fetchScriptByte(); - subOp -= 46; switch (subOp) { - case -14: // HE99+ + case 32: // HE99+ _wizParams.processFlags |= kWPFUseDefImgWidth; _wizParams.resDefImgW = pop(); break; - case -13: // HE99+ + case 33: // HE99+ _wizParams.processFlags |= kWPFUseDefImgHeight; _wizParams.resDefImgH = pop(); break; - case 0: + case 46: // Dummy case pop(); break; - case 1: + case 47: _wizParams.box.bottom = pop(); _wizParams.box.right = pop(); _wizParams.box.top = pop(); _wizParams.box.left = pop(); break; - case 2: + case 48: _wizParams.processMode = 1; break; - case 3: + case 49: _wizParams.processFlags |= kWPFUseFile; _wizParams.processMode = 3; copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); break; - case 4: + case 50: _wizParams.processFlags |= kWPFUseFile; _wizParams.processMode = 4; copyScriptString(_wizParams.filename, sizeof(_wizParams.filename)); _wizParams.fileWriteMode = pop(); break; - case 5: + case 51: _wizParams.processFlags |= kWPFClipBox | 0x100; _wizParams.processMode = 2; _wizParams.box.bottom = pop(); @@ -440,19 +439,19 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.compType = pop(); adjustRect(_wizParams.box); break; - case 6: + case 52: _wizParams.processFlags |= kWPFNewState; _wizParams.img.state = pop(); break; - case 7: + case 53: _wizParams.processFlags |= kWPFRotate; _wizParams.angle = pop(); break; - case 8: + case 54: _wizParams.processFlags |= kWPFNewFlags; _wizParams.img.flags |= pop(); break; - case 10: + case 56: _wizParams.img.flags = pop(); _wizParams.img.state = pop(); _wizParams.img.y1 = pop(); @@ -460,7 +459,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.img.resNum = pop(); _wiz->displayWizImage(&_wizParams.img); break; - case 11: + case 57: _wizParams.img.resNum = pop(); _wizParams.processMode = 0; _wizParams.processFlags = 0; @@ -471,18 +470,18 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.spriteId = 0; _wizParams.spriteGroup = 0; break; - case 16: // HE99+ + case 62: // HE99+ _wizParams.processFlags |= kWPFMaskImg; _wizParams.sourceImage = pop(); break; - case 19: - case 108: + case 65: + case 154: _wizParams.processFlags |= kWPFSetPos; _wizParams.img.y1 = pop(); _wizParams.img.x1 = pop(); break; - case 20: - case 203: // HE98+ + case 66: + case 249: // HE98+ b = pop(); a = pop(); _wizParams.processFlags |= kWPFRemapPalette; @@ -495,7 +494,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.remapColor[a] = b; _wizParams.remapNum++; break; - case 21: + case 67: _wizParams.processFlags |= kWPFClipBox; _wizParams.box.bottom = pop(); _wizParams.box.right = pop(); @@ -503,26 +502,26 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.box.left = pop(); adjustRect(_wizParams.box); break; - case 40: // HE99+ + case 86: // HE99+ _wizParams.processFlags |= kWPFPaletteNum; _wizParams.img.palette = pop(); break; - case 46: + case 92: _wizParams.processFlags |= kWPFScaled; _wizParams.scale = pop(); break; - case 52: + case 98: _wizParams.processFlags |= kWPFShadow; _wizParams.img.shadow = pop(); break; - case 85: // HE99+ + case 131: // HE99+ _wizParams.processFlags |= 0x1000 | 0x100 | 0x2; _wizParams.processMode = 7; _wizParams.polygonId2 = pop(); _wizParams.polygonId1 = pop(); _wizParams.compType = pop(); break; - case 87: // HE99+ + case 133: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; _wizParams.processMode = 9; _wizParams.fillColor = pop(); @@ -531,7 +530,7 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); break; - case 88: // HE99+ + case 134: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; _wizParams.processMode = 10; _wizParams.fillColor = pop(); @@ -540,33 +539,33 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.box2.top = pop(); _wizParams.box2.left = pop(); break; - case 89: // HE99+ + case 135: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; _wizParams.processMode = 11; _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); break; - case 90: // HE99+ + case 136: // HE99+ _wizParams.processFlags |= kWPFFillColor | kWPFClipBox2; _wizParams.processMode = 12; _wizParams.fillColor = pop(); _wizParams.box2.top = _wizParams.box2.bottom = pop(); _wizParams.box2.left = _wizParams.box2.right = pop(); break; - case 91: // HE99+ + case 137: // HE99+ _wizParams.processFlags |= kWPFDstResNum; _wizParams.dstResNum = pop(); break; - case 93: // HE99+ + case 139: // HE99+ _wizParams.processFlags |= kWPFThickLine; _wizParams.lineUnk1 = pop(); _wizParams.lineUnk2 = pop(); break; - case 95: // HE99+ + case 141: // HE99+ _wizParams.processMode = 13; break; - case 96: // HE99+ + case 142: // HE99+ _wizParams.field_239D = pop(); _wizParams.field_2399 = pop(); _wizParams.field_23A5 = pop(); @@ -574,13 +573,13 @@ void ScummEngine_v90he::o90_wizImageOps() { copyScriptString(_wizParams.string2, sizeof(_wizParams.string2)); _wizParams.processMode = 15; break; - case 97: // HE99+ + case 143: // HE99+ _wizParams.processMode = 16; _wizParams.field_23AD = pop(); _wizParams.field_23A9 = pop(); copyScriptString(_wizParams.string1, sizeof(_wizParams.string1)); break; - case 143: // HE99+ + case 189: // HE99+ _wizParams.processMode = 17; _wizParams.field_23CD = pop(); _wizParams.field_23C9 = pop(); @@ -591,18 +590,18 @@ void ScummEngine_v90he::o90_wizImageOps() { _wizParams.field_23B5 = pop(); _wizParams.field_23B1 = pop(); break; - case 150: // HE99+ + case 196: // HE99+ _wizParams.processMode = 14; break; - case 171: // HE99+ + case 217: // HE99+ _wizParams.processMode = 8; break; - case 200: + case 246: _wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2; _wizParams.img.flags |= kWIFIsPolygon; _wizParams.polygonId1 = _wizParams.img.y1 = _wizParams.img.x1 = pop(); break; - case 209: + case 255: if (_wizParams.img.resNum) _wiz->processWizImage(&_wizParams); break; @@ -724,10 +723,9 @@ void ScummEngine_v90he::o90_getSpriteInfo() { int32 x, y; byte subOp = fetchScriptByte(); - subOp -= 30; switch (subOp) { - case 0: + case 30: spriteId = pop(); if (spriteId) { _sprite->getSpritePosition(spriteId, x, y); @@ -736,7 +734,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 1: + case 31: spriteId = pop(); if (spriteId) { _sprite->getSpritePosition(spriteId, x, y); @@ -745,7 +743,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 2: + case 32: spriteId = pop(); if (spriteId) { _sprite->getSpriteImageDim(spriteId, x, y); @@ -754,7 +752,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 3: + case 33: spriteId = pop(); if (spriteId) { _sprite->getSpriteImageDim(spriteId, x, y); @@ -763,7 +761,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 4: + case 34: spriteId = pop(); if (spriteId) { _sprite->getSpriteDist(spriteId, x, y); @@ -772,7 +770,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 5: + case 35: spriteId = pop(); if (spriteId) { _sprite->getSpriteDist(spriteId, x, y); @@ -781,35 +779,35 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 6: + case 36: spriteId = pop(); if (spriteId) push(_sprite->getSpriteImageStateCount(spriteId)); else push(0); break; - case 7: + case 37: spriteId = pop(); if (spriteId) push(_sprite->getSpriteGroup(spriteId)); else push(0); break; - case 8: + case 38: spriteId = pop(); if (spriteId) push(_sprite->getSpriteDisplayX(spriteId)); else push(0); break; - case 9: + case 39: spriteId = pop(); if (spriteId) push(_sprite->getSpriteDisplayY(spriteId)); else push(0); break; - case 12: + case 42: flags = pop(); spriteId = pop(); if (spriteId) { @@ -836,14 +834,14 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 13: + case 43: spriteId = pop(); if (spriteId) push(_sprite->getSpritePriority(spriteId)); else push(0); break; - case 15: + case 45: if (_game.heversion == 99) { flags = getStackList(args, ARRAYSIZE(args)); type = pop(); @@ -864,77 +862,77 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(_sprite->findSpriteWithClassOf(x, y, groupId, 0, 0, 0)); } break; - case 22: + case 52: spriteId = pop(); if (spriteId) push(_sprite->getSpriteImageState(spriteId)); else push(0); break; - case 32: + case 62: spriteId = pop(); if (spriteId) push(_sprite->getSpriteSourceImage(spriteId)); else push(0); break; - case 33: + case 63: spriteId = pop(); if (spriteId) push(_sprite->getSpriteImage(spriteId)); else push(0); break; - case 38: + case 68: spriteId = pop(); if (spriteId) push(_sprite->getSpriteFlagEraseType(spriteId)); else push(1); break; - case 52: + case 82: spriteId = pop(); if (spriteId) push(_sprite->getSpriteFlagAutoAnim(spriteId)); else push(0); break; - case 56: + case 86: spriteId = pop(); if (spriteId) push(_sprite->getSpritePalette(spriteId)); else push(0); break; - case 62: + case 92: spriteId = pop(); if (spriteId) push(_sprite->getSpriteScale(spriteId)); else push(0); break; - case 67: + case 97: spriteId = pop(); if (spriteId) push(_sprite->getSpriteAnimSpeed(spriteId)); else push(1); break; - case 68: + case 98: spriteId = pop(); if (spriteId) push(_sprite->getSpriteShadow(spriteId)); else push(0); break; - case 94: + case 124: spriteId = pop(); if (spriteId) push(_sprite->getSpriteFlagUpdateType(spriteId)); else push(0); break; - case 95: + case 125: flags = getStackList(args, ARRAYSIZE(args)); spriteId = pop(); if (spriteId) { @@ -943,7 +941,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() { push(0); } break; - case 109: + case 139: flags = pop(); spriteId = pop(); if (spriteId) @@ -951,14 +949,14 @@ void ScummEngine_v90he::o90_getSpriteInfo() { else push(0); break; - case 110: + case 140: spriteId = pop(); if (spriteId) push(_sprite->getSpriteMaskImage(spriteId)); else push(0); break; - case 168: + case 198: pop(); spriteId = pop(); if (spriteId) @@ -978,10 +976,9 @@ void ScummEngine_v90he::o90_setSpriteInfo() { int n; byte subOp = fetchScriptByte(); - subOp -= 34; switch (subOp) { - case 0: + case 34: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -994,7 +991,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { _sprite->setSpriteDist(spriteId, args[0], tmp[1]); } break; - case 1: + case 35: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1007,7 +1004,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { _sprite->setSpriteDist(spriteId, tmp[0], args[0]); } break; - case 3: + case 37: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1018,7 +1015,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteGroup(spriteId, args[0]); break; - case 8: + case 42: args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1048,7 +1045,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { break; } break; - case 9: + case 43: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1059,7 +1056,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpritePriority(spriteId, args[0]); break; - case 10: + case 44: args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1071,7 +1068,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->moveSprite(spriteId, args[0], args[1]); break; - case 18: + case 52: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1082,7 +1079,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteImageState(spriteId, args[0]); break; - case 19: + case 53: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1093,7 +1090,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteAngle(spriteId, args[0]); break; - case 23: + case 57: if (_game.features & GF_HE_985 || _game.heversion >= 99) { _curMaxSpriteId = pop(); _curSpriteId = pop(); @@ -1105,7 +1102,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { _curMaxSpriteId = _curSpriteId; // to make all functions happy } break; - case 28: // HE99+ + case 62: // HE99+ args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1116,7 +1113,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteSourceImage(spriteId, args[0]); break; - case 29: + case 63: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1127,7 +1124,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteImage(spriteId, args[0]); break; - case 31: + case 65: args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1139,7 +1136,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpritePosition(spriteId, args[0], args[1]); break; - case 34: + case 68: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1150,7 +1147,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteFlagEraseType(spriteId, args[0]); break; - case 43: + case 77: args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1162,7 +1159,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteDist(spriteId, args[0], args[1]); break; - case 48: + case 82: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1173,7 +1170,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteFlagAutoAnim(spriteId, args[0]); break; - case 52: // HE 98+ + case 86: // HE 98+ args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1184,7 +1181,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpritePalette(spriteId, args[0]); break; - case 58: // HE 99+ + case 92: // HE 99+ args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1195,7 +1192,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteScale(spriteId, args[0]); break; - case 63: // HE 98+ + case 97: // HE 98+ args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1206,7 +1203,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteAnimSpeed(spriteId, args[0]); break; - case 64: + case 98: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1217,7 +1214,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteShadow(spriteId, args[0]); break; - case 90: + case 124: args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1228,7 +1225,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteFlagUpdateType(spriteId, args[0]); break; - case 91: + case 125: n = getStackList(args, ARRAYSIZE(args)); if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) { int *p = &args[n - 1]; @@ -1251,7 +1248,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { } while (--n); } break; - case 105: // HE 99+ + case 139: // HE 99+ args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1263,7 +1260,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]); break; - case 106: // HE 99+ + case 140: // HE 99+ args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) break; @@ -1274,10 +1271,10 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteMaskImage(spriteId, args[0]); break; - case 124: + case 158: _sprite->resetTables(true); break; - case 164: + case 198: args[1] = pop(); args[0] = pop(); if (_curSpriteId > _curMaxSpriteId) @@ -1289,7 +1286,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() { for (; spriteId <= _curMaxSpriteId; spriteId++) _sprite->setSpriteUserValue(spriteId, args[0], args[1]); break; - case 183: + case 217: if (_curSpriteId > _curMaxSpriteId) break; spriteId = _curSpriteId; @@ -1389,10 +1386,9 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { int type, value1, value2, value3, value4; byte subOp = fetchScriptByte(); - subOp -= 37; switch (subOp) { - case 0: + case 37: type = pop() - 1; switch (type) { case 0: @@ -1455,7 +1451,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { error("o90_setSpriteGroupInfo subOp 0: Unknown case %d", subOp); } break; - case 5: + case 42: type = pop(); value1 = pop(); if (!_curSpriteGroupId) @@ -1478,14 +1474,14 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { error("o90_setSpriteGroupInfo subOp 5: Unknown case %d", subOp); } break; - case 6: + case 43: value1 = pop(); if (!_curSpriteGroupId) break; _sprite->setGroupPriority(_curSpriteGroupId, value1); break; - case 7: + case 44: value2 = pop(); value1 = pop(); if (!_curSpriteGroupId) @@ -1493,17 +1489,17 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { _sprite->moveGroup(_curSpriteGroupId, value1, value2); break; - case 20: + case 57: _curSpriteGroupId = pop(); break; - case 26: + case 63: value1 = pop(); if (!_curSpriteGroupId) break; _sprite->setGroupImage(_curSpriteGroupId, value1); break; - case 28: + case 65: value2 = pop(); value1 = pop(); if (!_curSpriteGroupId) @@ -1511,7 +1507,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { _sprite->setGroupPosition(_curSpriteGroupId, value1, value2); break; - case 30: + case 67: value4 = pop(); value3 = pop(); value2 = pop(); @@ -1521,13 +1517,13 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() { _sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4); break; - case 56: + case 93: if (!_curSpriteGroupId) break; _sprite->resetGroupBounds(_curSpriteGroupId); break; - case 180: + case 217: if (!_curSpriteGroupId) break; @@ -1545,52 +1541,51 @@ void ScummEngine_v90he::o90_getWizData() { int32 x, y; byte subOp = fetchScriptByte(); - subOp -= 30; switch (subOp) { - case 0: + case 30: state = pop(); resId = pop(); _wiz->getWizImageSpot(resId, state, x, y); push(x); break; - case 1: + case 31: state = pop(); resId = pop(); _wiz->getWizImageSpot(resId, state, x, y); push(y); break; - case 2: + case 32: state = pop(); resId = pop(); _wiz->getWizImageDim(resId, state, w, h); push(w); break; - case 3: + case 33: state = pop(); resId = pop(); _wiz->getWizImageDim(resId, state, w, h); push(h); break; - case 6: + case 36: resId = pop(); push(_wiz->getWizImageStates(resId)); break; - case 15: + case 45: y = pop(); x = pop(); state = pop(); resId = pop(); push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0)); break; - case 36: + case 66: y = pop(); x = pop(); state = pop(); resId = pop(); push(_wiz->getWizPixelColor(resId, state, x, y, 0)); break; - case 100: + case 130: h = pop(); w = pop(); y = pop(); @@ -1604,12 +1599,12 @@ void ScummEngine_v90he::o90_getWizData() { } push(computeWizHistogram(resId, state, x, y, w, h)); break; - case 109: + case 139: pop(); pop(); push(0); break; - case 111: + case 141: pop(); copyScriptString(filename, sizeof(filename)); pop(); @@ -1730,30 +1725,29 @@ void ScummEngine_v90he::o90_videoOps() { void ScummEngine_v90he::o90_getVideoData() { // Uses Smacker video byte subOp = fetchScriptByte(); - subOp -= 32; switch (subOp) { - case 0: // Get width + case 32: // Get width pop(); push(_moviePlay->getWidth()); break; - case 1: // Get height + case 33: // Get height pop(); push(_moviePlay->getHeight()); break; - case 4: // Get frame count + case 36: // Get frame count pop(); push(_moviePlay->getFrameCount()); break; - case 20: // Get current frame + case 52: // Get current frame pop(); push(_moviePlay->getCurFrame()); break; - case 31: // Get image number + case 63: // Get image number pop(); push(_moviePlay->getImageNum()); break; - case 107: // Get statistics + case 139: // Get statistics debug(0, "o90_getVideoData: subOp 107 stub (%d, %d)", pop(), pop()); push(0); break; @@ -1764,33 +1758,32 @@ void ScummEngine_v90he::o90_getVideoData() { void ScummEngine_v90he::o90_floodFill() { byte subOp = fetchScriptByte(); - subOp -= 54; switch (subOp) { - case 0: + case 54: pop(); break; - case 3: + case 57: memset(&_floodFillParams, 0, sizeof(_floodFillParams)); _floodFillParams.box.left = 0; _floodFillParams.box.top = 0; _floodFillParams.box.right = 639; _floodFillParams.box.bottom = 479; break; - case 11: + case 65: _floodFillParams.y = pop(); _floodFillParams.x = pop(); break; - case 12: + case 66: _floodFillParams.flags = pop(); break; - case 13: + case 67: _floodFillParams.box.bottom = pop(); _floodFillParams.box.right = pop(); _floodFillParams.box.top = pop(); _floodFillParams.box.left = pop(); break; - case 201: + case 255: floodFill(&_floodFillParams, this); break; default: @@ -2336,47 +2329,46 @@ void ScummEngine_v90he::o90_sortArray() { void ScummEngine_v90he::o90_getObjectData() { byte subOp = fetchScriptByte(); - subOp -= 32; switch (subOp) { - case 0: + case 32: if (_heObjectNum == -1) push(0); else push(_objs[_heObjectNum].width); break; - case 1: + case 33: if (_heObjectNum == -1) push(0); else push(_objs[_heObjectNum].height); break; - case 4: + case 36: if (_heObjectNum == -1) push(0); else push(getObjectImageCount(_heObject)); break; - case 6: + case 38: if (_heObjectNum == -1) push(0); else push(_objs[_heObjectNum].x_pos); break; - case 7: + case 39: if (_heObjectNum == -1) push(0); else push(_objs[_heObjectNum].y_pos); break; - case 20: + case 52: push(getState(_heObject)); break; - case 25: + case 57: _heObject = pop(); _heObjectNum = getObjectIndex(_heObject); break; - case 107: + case 139: // Dummy case pop(); push(0); @@ -2391,10 +2383,9 @@ void ScummEngine_v90he::o90_getPaletteData() { int palSlot, color; byte subOp = fetchScriptByte(); - subOp -= 45; switch (subOp) { - case 0: + case 45: e = pop(); d = pop(); palSlot = pop(); @@ -2403,23 +2394,23 @@ void ScummEngine_v90he::o90_getPaletteData() { b = pop(); push(getHEPaletteSimilarColor(palSlot, b, c, d, e)); break; - case 7: + case 52: c = pop(); b = pop(); palSlot = pop(); push(getHEPaletteColorComponent(palSlot, b, c)); break; - case 21: + case 66: color = pop(); palSlot = pop(); push(getHEPaletteColor(palSlot, color)); break; - case 87: + case 132: c = pop(); b = pop(); push(getHEPaletteColorComponent(1, b, c)); break; - case 172: + case 217: pop(); c = pop(); c = MAX(0, c); @@ -2438,20 +2429,19 @@ void ScummEngine_v90he::o90_paletteOps() { int a, b, c, d, e; byte subOp = fetchScriptByte(); - subOp -= 57; switch (subOp) { - case 0: + case 57: _hePaletteNum = pop(); break; - case 6: + case 63: b = pop(); a = pop(); if (_hePaletteNum != 0) { setHEPaletteFromImage(_hePaletteNum, a, b); } break; - case 9: + case 66: e = pop(); d = pop(); c = pop(); @@ -2463,7 +2453,7 @@ void ScummEngine_v90he::o90_paletteOps() { } } break; - case 13: + case 70: c = pop(); b = pop(); a = pop(); @@ -2473,31 +2463,31 @@ void ScummEngine_v90he::o90_paletteOps() { } } break; - case 19: //HE99+ + case 76: //HE99+ a = pop(); if (_hePaletteNum != 0) { setHEPaletteFromCostume(_hePaletteNum, a); } break; - case 29: + case 86: a = pop(); if (_hePaletteNum != 0) { copyHEPalette(_hePaletteNum, a); } break; - case 118: + case 175: b = pop(); a = pop(); if (_hePaletteNum != 0) { setHEPaletteFromRoom(_hePaletteNum, a, b); } break; - case 160: + case 217: if (_hePaletteNum != 0) { restoreHEPalette(_hePaletteNum); } break; - case 198: + case 255: _hePaletteNum = 0; break; default: diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 35028c7e1c..bb67f2b31d 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -192,10 +192,6 @@ void ScummEngine::parseEvents() { _keyPressed = Common::KeyState(Common::KEYCODE_6, 54); // '6' break; - case Common::EVENT_QUIT: - _quit = true; - break; - default: break; } @@ -475,7 +471,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0) runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0); - mainMenuDialog(); // Display NewGui + scummMenuDialog(); // Display NewGui if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0) runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0); @@ -514,7 +510,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { vol = Audio::Mixer::kMaxMixerVolume; ConfMan.setInt("music_volume", vol); - updateSoundSettings(); + syncSoundSettings(); } else if (lastKeyHit.ascii == '-' || lastKeyHit.ascii == '+') { // Change text speed if (lastKeyHit.ascii == '+' && _defaultTalkDelay > 0) @@ -527,7 +523,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { _defaultTalkDelay = 9 - runDialog(dlg); // Save the new talkspeed value to ConfMan - setTalkspeed(_defaultTalkDelay); + setTalkDelay(_defaultTalkDelay); if (VAR_CHARINC != 0xFF) VAR(VAR_CHARINC) = _defaultTalkDelay; diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp index 1771618822..77a01d54d0 100644 --- a/engines/scumm/insane/insane.cpp +++ b/engines/scumm/insane/insane.cpp @@ -39,7 +39,6 @@ #include "scumm/smush/smush_player.h" #include "scumm/smush/smush_font.h" -#include "scumm/smush/chunk.h" #include "scumm/insane/insane.h" @@ -1310,33 +1309,25 @@ void Insane::smlayer_showStatusMsg(int32 arg_0, byte *renderBitmap, int32 codecp free (string); } -void Insane::procSKIP(Chunk &b) { +void Insane::procSKIP(int32 subSize, Common::SeekableReadStream &b) { int16 par1, par2; _player->_skipNext = false; if ((_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC)) { - _player->checkBlock(b, MKID_BE('SKIP'), 2); + assert(subSize >= 2); par1 = b.readUint16LE(); - if (isBitSet(par1)) - _player->_skipNext = true; - return; + par2 = 0; + } else { + assert(subSize >= 4); + par1 = b.readUint16LE(); + par2 = b.readUint16LE(); } - _player->checkBlock(b, MKID_BE('SKIP'), 4); - - par1 = b.readUint16LE(); - par2 = b.readUint16LE(); - - if (!par2) { if (isBitSet(par1)) _player->_skipNext = true; - return; - } - - if (isBitSet(par1) != isBitSet(par2)) { + } else if (isBitSet(par1) != isBitSet(par2)) { _player->_skipNext = true; - return; } } diff --git a/engines/scumm/insane/insane.h b/engines/scumm/insane/insane.h index 28eafb6f73..50d8d057cf 100644 --- a/engines/scumm/insane/insane.h +++ b/engines/scumm/insane/insane.h @@ -31,7 +31,6 @@ #include "scumm/nut_renderer.h" #include "scumm/smush/smush_player.h" -#include "scumm/smush/chunk.h" namespace Scumm { @@ -67,9 +66,9 @@ class Insane { void procPostRendering(byte *renderBitmap, int32 codecparam, int32 setupsan12, int32 setupsan13, int32 curFrame, int32 maxFrame); void procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, int16 par1, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); - void procSKIP(Chunk &b); + void procSKIP(int32 subSize, Common::SeekableReadStream &b); void escapeKeyHandler(void); private: @@ -434,22 +433,22 @@ class Insane { void ouchSoundEnemy(void); bool weaponEnemyIsEffective(void); void iactScene1(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); void iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 command, int16 par1, int16, int16); void iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); void iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); void iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); void iactScene21(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4); bool isBitSet(int n); void setBit(int n); diff --git a/engines/scumm/insane/insane_iact.cpp b/engines/scumm/insane/insane_iact.cpp index c7f0c7220b..b6ce1091e8 100644 --- a/engines/scumm/insane/insane_iact.cpp +++ b/engines/scumm/insane/insane_iact.cpp @@ -30,14 +30,13 @@ #include "scumm/scumm.h" #include "scumm/smush/smush_player.h" -#include "scumm/smush/chunk.h" #include "scumm/insane/insane.h" namespace Scumm { void Insane::procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { if (_keyboardDisable) return; @@ -67,7 +66,7 @@ void Insane::procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12, } void Insane::iactScene1(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { int16 par5, par6, par7, par9, par11, par13, tmp; @@ -294,7 +293,7 @@ void Insane::removeEnemyFromMetList(int32 enemy1) { } void Insane::iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 command, int16 par1, int16, int16) { int par2, par3; if (command == 6) { @@ -317,7 +316,7 @@ void Insane::iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12, } void Insane::iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { int16 par5; @@ -393,7 +392,7 @@ void Insane::iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12, } void Insane::iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { int16 par5; @@ -478,7 +477,7 @@ void Insane::iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12, } void Insane::iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { switch (par1) { case 2: @@ -524,7 +523,7 @@ void Insane::iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12, } void Insane::iactScene21(byte *renderBitmap, int32 codecparam, int32 setupsan12, - int32 setupsan13, Chunk &b, int32 size, int32 flags, + int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1, int16 par2, int16 par3, int16 par4) { // void implementation } diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index 7d52a02116..8d6a5453df 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -53,7 +53,6 @@ MODULE_OBJS := \ scumm.o \ sound.o \ string.o \ - thumbnail.o \ usage_bits.o \ util.o \ vars.o \ @@ -82,7 +81,6 @@ MODULE_OBJS += \ insane/insane_scenes.o \ insane/insane_iact.o \ smush/channel.o \ - smush/chunk.o \ smush/codec1.o \ smush/codec37.o \ smush/codec47.o \ diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index 6bd62c1761..50e0d221ca 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -226,7 +226,7 @@ void ScummEngine::askForDisk(const char *filename, int disknum) { #ifdef MACOSX sprintf(buf, "Cannot find file: '%s'\nPlease insert disc %d.\nPress OK to retry, Quit to exit", filename, disknum); #else - sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataPath.c_str()); + sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataDir.getPath().c_str()); #endif result = displayMessage("Quit", buf); @@ -253,7 +253,7 @@ void ScummEngine::readIndexFile() { if (_game.version <= 5) { // Figure out the sizes of various resources - while (!_fileHandle->eof()) { + while (!_fileHandle->eos()) { blocktype = _fileHandle->readUint32BE(); itemsize = _fileHandle->readUint32BE(); if (_fileHandle->ioFailed()) @@ -291,7 +291,7 @@ void ScummEngine::readIndexFile() { if (checkTryMedia(_fileHandle)) { displayMessage(NULL, "You're trying to run game encrypted by ActiveMark. This is not supported."); - _quit = true; + quitGame(); return; } @@ -809,7 +809,7 @@ byte *ResourceManager::createResource(int type, int idx, uint32 size) { ptr = (byte *)calloc(size + sizeof(MemBlkHeader) + SAFETY_AREA, 1); if (ptr == NULL) { - error("Out of memory while allocating %d", size); + error("createResource(%s,%d): Out of memory while allocating %d", resTypeFromId(type), idx, size); } _allocatedSize += size; diff --git a/engines/scumm/resource_v4.cpp b/engines/scumm/resource_v4.cpp index 0ced00e254..29d7c5d25d 100644 --- a/engines/scumm/resource_v4.cpp +++ b/engines/scumm/resource_v4.cpp @@ -62,7 +62,7 @@ void ScummEngine_v4::readIndexFile() { closeRoom(); openRoom(0); - while (!_fileHandle->eof()) { + while (!_fileHandle->eos()) { // Figure out the sizes of various resources itemsize = _fileHandle->readUint32LE(); blocktype = _fileHandle->readUint16LE(); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 54dfca9eea..267e06dafd 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -46,6 +46,8 @@ #include "sound/audiocd.h" #include "sound/mixer.h" +#include "graphics/thumbnail.h" + namespace Scumm { struct SaveGameHeader { @@ -71,6 +73,8 @@ struct SaveInfoSection { #define INFOSECTION_VERSION 2 +#pragma mark - + void ScummEngine::requestSave(int slot, const char *name, bool temporary) { _saveLoadSlot = slot; _saveTemporaryState = temporary; @@ -99,34 +103,36 @@ static bool saveSaveGameHeader(Common::OutSaveFile *out, SaveGameHeader &hdr) { } bool ScummEngine::saveState(int slot, bool compat) { - char filename[256]; + Common::String filename; Common::OutSaveFile *out; SaveGameHeader hdr; if (_saveLoadSlot == 255) { // Allow custom filenames for save game system in HE Games - memcpy(filename, _saveLoadFileName, sizeof(_saveLoadFileName)); + filename = _saveLoadFileName; } else { - makeSavegameName(filename, slot, compat); + filename = makeSavegameName(slot, compat); } - if (!(out = _saveFileMan->openForSaving(filename))) + if (!(out = _saveFileMan->openForSaving(filename.c_str()))) return false; memcpy(hdr.name, _saveLoadName, sizeof(hdr.name)); saveSaveGameHeader(out, hdr); - saveThumbnail(out); +#if !defined(__DS__) + Graphics::saveThumbnail(*out); +#endif saveInfos(out); Serializer ser(0, out, CURRENT_VER); saveOrLoad(&ser); out->finalize(); - if (out->ioFailed()) { + if (out->err()) { delete out; - debug(1, "State save as '%s' FAILED", filename); + debug(1, "State save as '%s' FAILED", filename.c_str()); return false; } delete out; - debug(1, "State saved as '%s'", filename); + debug(1, "State saved as '%s'", filename.c_str()); return true; } @@ -135,11 +141,11 @@ static bool loadSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &h hdr.size = in->readUint32LE(); hdr.ver = in->readUint32LE(); in->read(hdr.name, sizeof(hdr.name)); - return !in->ioFailed() && hdr.type == MKID_BE('SCVM'); + return !in->err() && hdr.type == MKID_BE('SCVM'); } bool ScummEngine::loadState(int slot, bool compat) { - char filename[256]; + Common::String filename; Common::SeekableReadStream *in; int i, j; SaveGameHeader hdr; @@ -147,15 +153,15 @@ bool ScummEngine::loadState(int slot, bool compat) { if (_saveLoadSlot == 255) { // Allow custom filenames for save game system in HE Games - memcpy(filename, _saveLoadFileName, sizeof(_saveLoadFileName)); + filename = _saveLoadFileName; } else { - makeSavegameName(filename, slot, compat); + filename = makeSavegameName(slot, compat); } - if (!(in = _saveFileMan->openForLoading(filename))) + if (!(in = _saveFileMan->openForLoading(filename.c_str()))) return false; if (!loadSaveGameHeader(in, hdr)) { - warning("Invalid savegame '%s'", filename); + warning("Invalid savegame '%s'", filename.c_str()); delete in; return false; } @@ -171,30 +177,30 @@ bool ScummEngine::loadState(int slot, bool compat) { // to work around a bug from the stone age (see below for more // information). if (hdr.ver < VER(7) || hdr.ver > CURRENT_VER) { - warning("Invalid version of '%s'", filename); + warning("Invalid version of '%s'", filename.c_str()); delete in; return false; } // We (deliberately) broke HE savegame compatibility at some point. if (hdr.ver < VER(50) && _game.heversion >= 71) { - warning("Unsupported version of '%s'", filename); + warning("Unsupported version of '%s'", filename.c_str()); delete in; return false; } // Since version 52 a thumbnail is saved directly after the header. if (hdr.ver >= VER(52)) { - uint32 type = in->readUint32BE(); - // Check for the THMB header. Also, work around a bug which caused - // the chunk type (incorrectly) to be written in LE on LE machines. - if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){ - warning("Can not load thumbnail"); - delete in; - return false; + // Prior to version 75 we always required an thumbnail to be present + if (hdr.ver <= VER(74)) { + if (!Graphics::checkThumbnailHeader(*in)) { + warning("Can not load thumbnail"); + delete in; + return false; + } } - uint32 size = in->readUint32BE(); - in->skip(size - 8); + + Graphics::skipThumbnailHeader(*in); } // Since version 56 we save additional information about the creation of @@ -275,7 +281,7 @@ bool ScummEngine::loadState(int slot, bool compat) { delete in; // Update volume settings - updateSoundSettings(); + syncSoundSettings(); // Init NES costume data if (_game.platform == Common::kPlatformNES) { @@ -385,7 +391,7 @@ bool ScummEngine::loadState(int slot, bool compat) { if (VAR_VOICE_MODE != 0xFF) VAR(VAR_VOICE_MODE) = ConfMan.getBool("subtitles"); - debug(1, "State loaded from '%s'", filename); + debug(1, "State loaded from '%s'", filename.c_str()); _sound->pauseSounds(false); @@ -401,23 +407,24 @@ bool ScummEngine::loadState(int slot, bool compat) { return true; } -void ScummEngine::makeSavegameName(char *out, int slot, bool temporary) { - sprintf(out, "%s.%c%.2d", _targetName.c_str(), temporary ? 'c' : 's', slot); +Common::String ScummEngine::makeSavegameName(const Common::String &target, int slot, bool temporary) { + char extension[6]; + snprintf(extension, sizeof(extension), ".%c%02d", temporary ? 'c' : 's', slot); + return (target + extension); } void ScummEngine::listSavegames(bool *marks, int num) { assert(marks); - char prefix[256]; char slot[3]; int slotNum; Common::StringList files; - makeSavegameName(prefix, 99, false); - prefix[strlen(prefix)-2] = '*'; - prefix[strlen(prefix)-1] = 0; + Common::String prefix = makeSavegameName(99, false); + prefix.setChar('*', prefix.size()-2); + prefix.setChar(0, prefix.size()-1); memset(marks, false, num * sizeof(bool)); //assume no savegames for this title - files = _saveFileMan->listSavefiles(prefix); + files = _saveFileMan->listSavefiles(prefix.c_str()); for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) { //Obtain the last 2 digits of the filename, since they correspond to the save slot @@ -436,11 +443,10 @@ bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion bool ScummEngine::getSavegameName(int slot, Common::String &desc) { Common::InSaveFile *in = 0; bool result = false; - char filename[256]; desc.clear(); - makeSavegameName(filename, slot, false); - in = _saveFileMan->openForLoading(filename); + Common::String filename = makeSavegameName(slot, false); + in = _saveFileMan->openForLoading(filename.c_str()); if (in) { result = Scumm::getSavegameName(in, desc, _game.heversion); delete in; @@ -474,16 +480,15 @@ bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion return true; } -Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) { - char filename[256]; +Graphics::Surface *ScummEngine::loadThumbnailFromSlot(const char *target, int slot) { Common::SeekableReadStream *in; SaveGameHeader hdr; if (slot < 0) return 0; - makeSavegameName(filename, slot, false); - if (!(in = _saveFileMan->openForLoading(filename))) { + Common::String filename = ScummEngine::makeSavegameName(target, slot, false); + if (!(in = g_system->getSavefileManager()->openForLoading(filename.c_str()))) { return 0; } @@ -499,22 +504,29 @@ Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) { return 0; } - Graphics::Surface *thumb = loadThumbnail(in); + Graphics::Surface *thumb = 0; + if (Graphics::checkThumbnailHeader(*in)) { + thumb = new Graphics::Surface(); + assert(thumb); + if (!Graphics::loadThumbnail(*in, *thumb)) { + delete thumb; + thumb = 0; + } + } delete in; return thumb; } -bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) { - char filename[256]; +bool ScummEngine::loadInfosFromSlot(const char *target, int slot, InfoStuff *stuff) { Common::SeekableReadStream *in; SaveGameHeader hdr; if (slot < 0) return 0; - makeSavegameName(filename, slot, false); - if (!(in = _saveFileMan->openForLoading(filename))) { + Common::String filename = makeSavegameName(target, slot, false); + if (!(in = g_system->getSavefileManager()->openForLoading(filename.c_str()))) { return false; } @@ -530,16 +542,8 @@ bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) { return false; } - uint32 type = in->readUint32BE(); - - // Check for the THMB header. Also, work around a bug which caused - // the chunk type (incorrectly) to be written in LE on LE machines. - if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){ - delete in; + if (!Graphics::skipThumbnailHeader(*in)) return false; - } - uint32 size = in->readUint32BE(); - in->skip(size - 8); if (!loadInfos(in, stuff)) { delete in; @@ -594,9 +598,8 @@ bool ScummEngine::loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff) stuff->playtime = section.playtime; // Skip over the remaining (unsupported) data - if (section.size > SaveInfoSectionSize) { + if (section.size > SaveInfoSectionSize) file->skip(section.size - SaveInfoSectionSize); - } return true; } diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h index 2d7ee64680..4f9899f961 100644 --- a/engines/scumm/saveload.h +++ b/engines/scumm/saveload.h @@ -50,7 +50,7 @@ namespace Scumm { * only saves/loads those which are valid for the version of the savegame * which is being loaded/saved currently. */ -#define CURRENT_VER 74 +#define CURRENT_VER 75 /** * An auxillary macro, used to specify savegame versions. We use this instead diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index c727b59c64..642627d649 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -625,10 +625,10 @@ void ScummEngine::writeVar(uint var, int value) { if (var == VAR_CHARINC) { if (ConfMan.hasKey("talkspeed")) { - value = getTalkspeed(); + value = getTalkDelay(); } else { // Save the new talkspeed value to ConfMan - setTalkspeed(value); + setTalkDelay(value); } } diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index 3cbb2b8266..c5c055249e 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -1769,7 +1769,7 @@ void ScummEngine_v5::o5_systemOps() { pauseGame(); break; case 3: // SO_QUIT - shutDown(); + quitGame(); break; default: error("o5_systemOps: unknown subopcode %d", subOp); diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index b9a00e6d38..c8534396db 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -2310,7 +2310,7 @@ void ScummEngine_v6::o6_systemOps() { pauseGame(); break; case 160: // SO_QUIT - shutDown(); + quitGame(); break; default: error("o6_systemOps invalid case %d", subOp); @@ -2374,7 +2374,7 @@ void ScummEngine_v6::o6_printEgo() { void ScummEngine_v6::o6_talkActor() { int offset = _scriptPointer - _scriptOrgPointer; - // WORKAROUNDfor bug #896489: see below for detailed description + // WORKAROUND for bug #896489: see below for detailed description if (_forcedWaitForMessage) { if (VAR(VAR_HAVE_MSG)) { _scriptPointer--; diff --git a/engines/scumm/script_v8.cpp b/engines/scumm/script_v8.cpp index 08629afb07..8859435dc9 100644 --- a/engines/scumm/script_v8.cpp +++ b/engines/scumm/script_v8.cpp @@ -424,10 +424,10 @@ void ScummEngine_v8::writeVar(uint var, int value) { if (var == VAR_CHARINC) { if (ConfMan.hasKey("talkspeed")) { - value = getTalkspeed(); + value = getTalkDelay(); } else { // Save the new talkspeed value to ConfMan - setTalkspeed(value); + setTalkDelay(value); } } @@ -1170,7 +1170,7 @@ void ScummEngine_v8::o8_systemOps() { restart(); break; case 0x29: // SO_SYSTEM_QUIT Quit game - shutDown(); + quitGame(); break; default: error("o8_systemOps: invalid case 0x%x", subOp); @@ -1289,7 +1289,7 @@ void ScummEngine_v8::o8_kernelSetFunctions() { if (ConfMan.getBool("confirm_exit")) confirmExitDialog(); else - _quit = true; + quitGame(); break; case 108: // buildPaletteShadow setShadowPalette(args[1], args[2], args[3], args[4], args[5], args[6]); diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index ce8f0a4d9a..9c076ddfc8 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Mon Jul 28 00:13:01 2008 + This file was generated by the md5table tool on Sat Sep 06 07:02:46 2008 DO NOT EDIT MANUALLY! */ @@ -54,6 +54,7 @@ static const MD5Table md5table[] = { { "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows }, { "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, { "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST }, + { "0f9d3317910ac7a9f449243118884ada", "puttzoo", "", "", 42070, Common::DE_DEU, Common::kPlatformWindows }, { "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown }, { "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, @@ -63,6 +64,7 @@ static const MD5Table md5table[] = { { "11e6e244078ff09b0f3832e35420e0a7", "catalog", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "132bff65e6367c09cc69318ce1b59333", "monkey2", "", "", 11155, Common::EN_ANY, Common::kPlatformAmiga }, { "1387d16aa620dc1c2d1fd87f8a9e7a09", "puttcircus", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, + { "13d2a86a7290813a1c386490447d72db", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "145bd3373574feb668cc2eea2ec6cf86", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "14d48c95b43ddeb983254cf6c43851f1", "freddi4", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -98,6 +100,7 @@ static const MD5Table md5table[] = { { "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows }, + { "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows }, { "20da6fce37805423966aaa8f3c2426aa", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, @@ -106,6 +109,7 @@ static const MD5Table md5table[] = { { "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", 262144, Common::SE_SWE, Common::kPlatformNES }, + { "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows }, { "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES }, @@ -144,6 +148,7 @@ static const MD5Table md5table[] = { { "362c1d281fb9899254cda66ad246c66a", "dig", "Demo", "Demo", 3472, Common::EN_ANY, Common::kPlatformUnknown }, { "3686cf8f89e102ececf4366e1d2c8126", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformPC }, { "36a6750e03fb505fc19fc2bf3e4dbe91", "pajama2", "", "Demo", 58749, Common::EN_ANY, Common::kPlatformUnknown }, + { "3769b56c9a22f5521d74525ee459f88d", "puttrace", "HE 99", "Demo", 13108, Common::DE_DEU, Common::kPlatformWindows }, { "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC }, { "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows }, @@ -201,6 +206,7 @@ static const MD5Table md5table[] = { { "4edbf9d03550f7ba01e7f34d69b678dd", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, + { "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 61", "", 7717, Common::EN_ANY, Common::kPlatformPC }, { "4f267a901719623de7dde83e47d5b474", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, { "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -208,6 +214,7 @@ static const MD5Table md5table[] = { { "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, { "5057fb0e99e5aa29df1836329232f101", "freddi2", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows }, + { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, { "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC }, { "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "513f91a9dbe8d5490b39e56a3ac5bbdf", "pajama2", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, @@ -221,6 +228,7 @@ static const MD5Table md5table[] = { { "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", 9800, Common::EN_ANY, Common::kPlatformWindows }, { "5798972220cd458be2626d54c80f71d7", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "57a17febe2183f521250e55d55b83e60", "PuttTime", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows }, + { "57a5cfec9ef231a007043cc1917e8988", "freddi", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, { "57b0d89af79befe1cabce3bece869e7f", "tentacle", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC }, { "58436e634f4fae1d9973591c2ffa1fcb", "spyfox", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "589601b676c98b1c0c987bc031ab68b3", "chase", "HE 95", "", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -244,6 +252,7 @@ static const MD5Table md5table[] = { { "6269b8fbf51a353e5b501e4ad98cdc67", "arttime", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "6271130f440066830eca9056c1d7926f", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "62b8c16b6db226ba95aaa8be73f9885c", "indy3", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformAmiga }, + { "632d2fddb8ba97723fa15334763ae857", "thinker1", "", "", 33270, Common::EN_ANY, Common::kPlatformWindows }, { "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 85", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "6508fd55530e6915507e1cc37f7f045d", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "65563295c3a06493351870f20a1630cf", "spyozon", "HE CUP", "Preview", 5235008, Common::UNK_LANG, Common::kPlatformUnknown }, @@ -272,6 +281,7 @@ static const MD5Table md5table[] = { { "6b27dbcd8d5697d5c918eeca0f68ef6a", "puttrace", "HE CUP", "Preview", 3901484, Common::UNK_LANG, Common::kPlatformUnknown }, { "6b3ec67da214f558dc5ceaa2acd47453", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "6b5a3fef241e90d4b2e77f1e222773ee", "maniac", "NES", "extracted", -1, Common::SE_SWE, Common::kPlatformNES }, + { "6bca7a1a96d16e52b8f3c42b50dbdca3", "fbear", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO }, { "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows }, { "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, @@ -296,14 +306,17 @@ static const MD5Table md5table[] = { { "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC }, { "7410a8ba9795020cd42f171c4320659e", "pajama3", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, + { "74da3494fbe1a7d20213b0afe0954755", "catalog", "HE CUP", "Preview", 10841544, Common::FR_FRA, Common::kPlatformUnknown }, { "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows }, { "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "75bff95816b84672b877d22a911ab811", "freddi3", "HE 99", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows }, { "76b66b43e593ad4d2f1dfb5cc8f19700", "spyfox", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "771bc18ec6f93837b839c992b211904b", "monkey", "Demo", "EGA Demo", -1, Common::DE_DEU, Common::kPlatformPC }, + { "7766c9487f9d53a8cb0edabda5119c3d", "puttputt", "HE 60", "", 8022, Common::EN_ANY, Common::kPlatformPC }, { "77f5c9cc0986eb729c1a6b4c8823bbae", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns }, { "780e4a0ae2ff17dc296f4a79543b44f8", "puttmoon", "", "", -1, Common::UNK_LANG, Common::kPlatformPC }, { "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "784b499c98d07260a30952685758636b", "pajama3", "", "Demo", 13911, Common::DE_DEU, Common::kPlatformWindows }, { "78bd5f036ea35a878b74e4f47941f784", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformPC }, @@ -322,6 +335,7 @@ static const MD5Table md5table[] = { { "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", 262144, Common::FR_FRA, Common::kPlatformNES }, { "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", 1916, Common::EN_ANY, Common::kPlatformAtariST }, { "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, + { "839a658f7d22de00787ebc945348cdb6", "dog", "", "", 19681, Common::DE_DEU, Common::kPlatformWindows }, { "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "84e3c23a49ded8a6f9197735c8eb3de7", "PuttTime", "HE 85", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "8539c0ff89868e55a08e652ac44daaae", "water", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -330,6 +344,7 @@ static const MD5Table md5table[] = { { "86c9902b7bec1a17926d4dae85beaa45", "airport", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "870d1e3c86bc50846d808d14a36b4e08", "monkey", "VGA", "VGA", -1, Common::ES_ESP, Common::kPlatformAmiga }, { "8776caed014c321272af407c1502a2df", "monkey", "CD", "", 8955, Common::EN_ANY, Common::kPlatformMacintosh }, + { "87df3e0074624040407764b7c5e710b9", "pajama", "", "Demo", 18354, Common::NL_NLD, Common::kPlatformWindows }, { "87f6e8037b7cc996e13474b491a7a98e", "maniac", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC }, { "8801fb4a1200b347f7a38523339526dd", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown }, @@ -394,12 +409,14 @@ static const MD5Table md5table[] = { { "a0a7dea72003933b8b3f8b99b9f7ddeb", "loom", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, { "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown }, { "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "a2386da005672cbd5136f4f27a626c5f", "farm", "", "", 87061, Common::NL_NLD, Common::kPlatformWindows }, { "a28135a7ade38cc0208b04507c46efd1", "spyfox", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "a2bb6aa0537402c1b3c2ea899ccef64b", "lost", "HE 99", "Demo", 15540, Common::EN_ANY, Common::kPlatformWindows }, { "a3036878840720fbefa41e6965fa4a0a", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC }, { "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown }, { "a570381b028972d891052ee1e51dc011", "maniac", "V2", "V2", -1, Common::EN_ANY, Common::kPlatformAtariST }, + { "a5c5388da9bf0e6662fdca8813a79d13", "farm", "", "", 86962, Common::EN_ANY, Common::kPlatformWindows }, { "a654fb60c3b67d6317a7894ffd9f25c5", "pajama3", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "a85856675429fe88051744f755b72f93", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -429,10 +446,13 @@ static const MD5Table md5table[] = { { "b886b0a5d909c7158a914e1d7c1c6c65", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC }, { "b8955d7d23b4972229060d1592489fef", "freddicove", "HE 100", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "b9ba19ce376efc69be78ef3baef8d2b9", "monkey", "CD", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, + { "b9bb68c5d2c9b6e2d9c513a29a754a57", "puttmoon", "", "", 7828, Common::EN_ANY, Common::kPlatformPC }, { "ba888e6831517597859e91aa173f945c", "spyfox", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "bab0fb81dcb12b8930c5d850b8f2a7de", "balloon", "HE 80", "", 12800, Common::DE_DEU, Common::kPlatformWindows }, { "bbadf7309c4a2c2763e4bbba3c3be634", "freddi3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "bc4700bc0e12879f6d25d14d6be6cfdd", "spyfox2", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "bd126753de619a495f9f22adc951c8d5", "monkey2", "", "", -1, Common::IT_ITA, Common::kPlatformPC }, + { "bd5fd7835335dfce03064d5f77b7f0ae", "dog", "", "", 19681, Common::NL_NLD, Common::kPlatformWindows }, { "be2abe172f58db170de3a037daa1dd27", "puttputt", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO }, { "be39a5d4db60e8aa736b9086778cb45c", "spyozon", "", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "be83e882b44f2767bc08d4f766ebc347", "maniac", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAtariST }, @@ -441,6 +461,7 @@ static const MD5Table md5table[] = { { "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "c0d5c89550381ac433624fedad5e1100", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, { "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD }, + { "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii }, { "c24c490373aeb48fbd54caa8e7ae376d", "loom", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "c25755b08a8d0d47695e05f1e2111bfc", "freddi4", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "c30ef068add4277104243c31ce46c12b", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformAmiga }, @@ -546,6 +567,7 @@ static const MD5Table md5table[] = { { "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, { "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, + { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO }, { "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC }, { "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC }, @@ -566,6 +588,7 @@ static const MD5Table md5table[] = { { "f8be685007a8b425ba2a455da732f59f", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "fa127d7c4bb47d05bb1c33ddcaa9f767", "loom", "EGA", "EGA", 5748, Common::DE_DEU, Common::kPlatformPC }, { "fa30c4a7a806629626269b6dcab59a15", "BluesBirthday", "HE CUP", "Preview", 7819264, Common::UNK_LANG, Common::kPlatformUnknown }, + { "fa84cb1018103a4ee4e5fa8041c1d0d1", "freddi4", "", "Demo", 13609, Common::DE_DEU, Common::kPlatformWindows }, { "fb66aa42de21675116346213f176a366", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 2f0593dca8..f87adfd9ac 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -109,7 +109,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _language(dr.language), _debugger(0), _currentScript(0xFF), // Let debug() work on init stage - _pauseDialog(0), _mainMenuDialog(0), _versionDialog(0) { + _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) { if (_game.platform == Common::kPlatformNES) { _gdi = new GdiNES(this); @@ -143,9 +143,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _objs = NULL; _sound = NULL; memset(&vm, 0, sizeof(vm)); - _quit = false; _pauseDialog = NULL; - _mainMenuDialog = NULL; + _scummMenuDialog = NULL; _versionDialog = NULL; _fastMode = 0; _actors = NULL; @@ -561,7 +560,7 @@ ScummEngine::~ScummEngine() { delete _2byteFontPtr; delete _charset; delete _pauseDialog; - delete _mainMenuDialog; + delete _scummMenuDialog; delete _versionDialog; delete _fileHandle; @@ -815,7 +814,6 @@ ScummEngine_vCUPhe::ScummEngine_vCUPhe(OSystem *syst, const DetectorResult &dr) _syst = syst; _game = dr.game; _filenamePattern = dr.fp, - _quit = false; _cupPlayer = new CUP_Player(syst, this, _mixer); } @@ -845,14 +843,13 @@ void ScummEngine_vCUPhe::parseEvents() { Common::Event event; while (_eventMan->pollEvent(event)) { +#if 0 switch (event.type) { - case Common::EVENT_QUIT: - _quit = true; - break; default: break; } +#endif } } @@ -916,20 +913,20 @@ int ScummEngine::init() { // Add default file directories. if (((_game.platform == Common::kPlatformAmiga) || (_game.platform == Common::kPlatformAtariST)) && (_game.version <= 4)) { // This is for the Amiga version of Indy3/Loom/Maniac/Zak - File::addDefaultDirectory(_gameDataPath + "ROOMS/"); - File::addDefaultDirectory(_gameDataPath + "rooms/"); + File::addDefaultDirectory(_gameDataDir.getChild("ROOMS")); + File::addDefaultDirectory(_gameDataDir.getChild("rooms")); } if ((_game.platform == Common::kPlatformMacintosh) && (_game.version == 3)) { // This is for the Mac version of Indy3/Loom - File::addDefaultDirectory(_gameDataPath + "Rooms 1/"); - File::addDefaultDirectory(_gameDataPath + "Rooms 2/"); - File::addDefaultDirectory(_gameDataPath + "Rooms 3/"); + File::addDefaultDirectory(_gameDataDir.getChild("Rooms 1")); + File::addDefaultDirectory(_gameDataDir.getChild("Rooms 2")); + File::addDefaultDirectory(_gameDataDir.getChild("Rooms 3")); } #ifdef ENABLE_SCUMM_7_8 #ifdef MACOSX - if (_game.version == 8 && !memcmp(_gameDataPath.c_str(), "/Volumes/MONKEY3_", 17)) { + if (_game.version == 8 && !memcmp(_gameDataDir.getPath().c_str(), "/Volumes/MONKEY3_", 17)) { // Special case for COMI on Mac OS X. The mount points on OS X depend // on the volume name. Hence if playing from CD, we'd get a problem. // So if loading of a resource file fails, we fall back to the (fixed) @@ -946,16 +943,16 @@ int ScummEngine::init() { #endif if (_game.version == 8) { // This is for COMI - File::addDefaultDirectory(_gameDataPath + "RESOURCE/"); - File::addDefaultDirectory(_gameDataPath + "resource/"); + File::addDefaultDirectory(_gameDataDir.getChild("RESOURCE")); + File::addDefaultDirectory(_gameDataDir.getChild("resource")); } if (_game.version == 7) { // This is for Full Throttle & The Dig - File::addDefaultDirectory(_gameDataPath + "VIDEO/"); - File::addDefaultDirectory(_gameDataPath + "video/"); - File::addDefaultDirectory(_gameDataPath + "DATA/"); - File::addDefaultDirectory(_gameDataPath + "data/"); + File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); + File::addDefaultDirectory(_gameDataDir.getChild("video")); + File::addDefaultDirectory(_gameDataDir.getChild("DATA")); + File::addDefaultDirectory(_gameDataDir.getChild("data")); } #endif @@ -1108,7 +1105,7 @@ int ScummEngine::init() { if (_game.version >= 5 && _game.version <= 7) _sound->setupSound(); - updateSoundSettings(); + syncSoundSettings(); return 0; } @@ -1533,6 +1530,12 @@ void ScummEngine_v99he::resetScumm() { byte *data = defineArray(129, kStringArray, 0, 0, 0, len); memcpy(data, _filenamePattern.pattern, len); } + +void ScummEngine_v100he::resetScumm() { + ScummEngine_v99he::resetScumm(); + + memset(_debugInputBuffer, 0, sizeof(_debugInputBuffer)); +} #endif void ScummEngine::setupMusic(int midi) { @@ -1667,7 +1670,7 @@ void ScummEngine::setupMusic(int midi) { } } -void ScummEngine::updateSoundSettings() { +void ScummEngine::syncSoundSettings() { // Sync the engine with the config manager int soundVolumeMusic = ConfMan.getInt("music_volume"); @@ -1690,17 +1693,17 @@ void ScummEngine::updateSoundSettings() { if (VAR_VOICE_MODE != 0xFF) VAR(VAR_VOICE_MODE) = _voiceMode; - _defaultTalkDelay = getTalkspeed(); + _defaultTalkDelay = getTalkDelay(); if (VAR_CHARINC != 0xFF) VAR(VAR_CHARINC) = _defaultTalkDelay; } -void ScummEngine::setTalkspeed(int talkspeed) { - ConfMan.setInt("talkspeed", (talkspeed * 255 + 9 / 2) / 9); +void ScummEngine::setTalkDelay(int talkdelay) { + ConfMan.setInt("talkspeed", ((9 - talkdelay) * 255 + 9 / 2) / 9); } -int ScummEngine::getTalkspeed() { - return (ConfMan.getInt("talkspeed") * 9 + 255 / 2) / 255; +int ScummEngine::getTalkDelay() { + return 9 - (ConfMan.getInt("talkspeed") * 9 + 255 / 2) / 255; } @@ -1721,7 +1724,7 @@ int ScummEngine::go() { int diff = 0; // Duration of one loop iteration - while (!_quit) { + while (!quit()) { if (_debugger->isAttached()) _debugger->onFrame(); @@ -1754,7 +1757,7 @@ int ScummEngine::go() { diff = _system->getMillis() - diff; - if (_quit) { + if (quit()) { // TODO: Maybe perform an autosave on exit? } } @@ -1772,7 +1775,7 @@ void ScummEngine::waitForTimer(int msec_delay) { start_time = _system->getMillis(); - while (!_quit) { + while (!quit()) { _sound->updateCD(); // Loop CD Audio if needed parseEvents(); _system->updateScreen(); @@ -1895,7 +1898,7 @@ load_game: checkExecVerbs(); checkAndRunSentenceScript(); - if (_quit) + if (quit()) return; // HACK: If a load was requested, immediately perform it. This avoids @@ -2011,7 +2014,6 @@ void ScummEngine::scummLoop_handleSaveLoad() { if (_saveLoadFlag) { bool success; const char *errMsg = 0; - char filename[256]; if (_game.version == 8 && _saveTemporaryState) VAR(VAR_GAME_LOADED) = 0; @@ -2032,13 +2034,13 @@ void ScummEngine::scummLoop_handleSaveLoad() { VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : 203; } - makeSavegameName(filename, _saveLoadSlot, _saveTemporaryState); + Common::String filename = makeSavegameName(_saveLoadSlot, _saveTemporaryState); if (!success) { - displayMessage(0, errMsg, filename); + displayMessage(0, errMsg, filename.c_str()); } else if (_saveLoadFlag == 1 && _saveLoadSlot != 0 && !_saveTemporaryState) { // Display "Save successful" message, except for auto saves char buf[256]; - snprintf(buf, sizeof(buf), "Successfully saved game state in file:\n\n%s", filename); + snprintf(buf, sizeof(buf), "Successfully saved game state in file:\n\n%s", filename.c_str()); GUI::TimedMessageDialog dialog(buf, 1500); runDialog(dialog); @@ -2160,10 +2162,6 @@ void ScummEngine::pauseGame() { pauseDialog(); } -void ScummEngine::shutDown() { - _quit = true; -} - void ScummEngine::restart() { // TODO: Check this function - we should probably be reinitting a lot more stuff, and I suspect // this leaks memory like a sieve @@ -2305,18 +2303,18 @@ void ScummEngine::versionDialog() { runDialog(*_versionDialog); } -void ScummEngine::mainMenuDialog() { - if (!_mainMenuDialog) - _mainMenuDialog = new MainMenuDialog(this); - runDialog(*_mainMenuDialog); - updateSoundSettings(); +void ScummEngine::scummMenuDialog() { + if (!_scummMenuDialog) + _scummMenuDialog = new ScummMenuDialog(this); + runDialog(*_scummMenuDialog); + syncSoundSettings(); } void ScummEngine::confirmExitDialog() { ConfirmDialog d(this, 6); if (runDialog(d)) { - _quit = true; + quitGame(); } } diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 2763331420..27c8943fee 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -462,9 +462,9 @@ protected: virtual void loadLanguageBundle() {} void loadCJKFont(); void setupMusic(int midi); - void updateSoundSettings(); - void setTalkspeed(int talkspeed); - int getTalkspeed(); + virtual void syncSoundSettings(); + void setTalkDelay(int talkdelay); + int getTalkDelay(); // Scumm main loop & helper functions. virtual void scummLoop(int delta); @@ -496,22 +496,18 @@ protected: public: void pauseGame(); void restart(); - void shutDown(); - - /** We keep running until this is set to true. */ - bool _quit; protected: Dialog *_pauseDialog; Dialog *_versionDialog; - Dialog *_mainMenuDialog; + Dialog *_scummMenuDialog; virtual int runDialog(Dialog &dialog); void confirmExitDialog(); void confirmRestartDialog(); void pauseDialog(); void versionDialog(); - void mainMenuDialog(); + void scummMenuDialog(); char displayMessage(const char *altButton, const char *message, ...); @@ -618,11 +614,16 @@ protected: void saveLoadResource(Serializer *ser, int type, int index); // "Obsolete" void saveResource(Serializer *ser, int type, int index); void loadResource(Serializer *ser, int type, int index); - void makeSavegameName(char *out, int slot, bool temporary); + + Common::String makeSavegameName(int slot, bool temporary) const { + return makeSavegameName(_targetName, slot, temporary); + } int getKeyState(int key); public: + static Common::String makeSavegameName(const Common::String &target, int slot, bool temporary); + bool getSavegameName(int slot, Common::String &desc); void listSavegames(bool *marks, int num); @@ -631,14 +632,19 @@ public: // thumbnail + info stuff public: - Graphics::Surface *loadThumbnailFromSlot(int slot); - bool loadInfosFromSlot(int slot, InfoStuff *stuff); + Graphics::Surface *loadThumbnailFromSlot(int slot) { + return loadThumbnailFromSlot(_targetName.c_str(), slot); + } + static Graphics::Surface *loadThumbnailFromSlot(const char *target, int slot); + + bool loadInfosFromSlot(int slot, InfoStuff *stuff) { + return loadInfosFromSlot(_targetName.c_str(), slot, stuff); + } + static bool loadInfosFromSlot(const char *target, int slot, InfoStuff *stuff); protected: - Graphics::Surface *loadThumbnail(Common::SeekableReadStream *file); - bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff); - void saveThumbnail(Common::WriteStream *file); void saveInfos(Common::WriteStream* file); + static bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff); int32 _engineStartTime; int32 _pauseStartTime; diff --git a/engines/scumm/smush/channel.h b/engines/scumm/smush/channel.h index 52fec22e0e..1e023e08ff 100644 --- a/engines/scumm/smush/channel.h +++ b/engines/scumm/smush/channel.h @@ -28,10 +28,11 @@ #include "common/util.h" -namespace Scumm { +namespace Common { + class SeekableReadStream; +} -class Chunk; -class ContChunk; +namespace Scumm { class SmushChannel { protected: @@ -55,7 +56,7 @@ protected: public: SmushChannel(int32 track); virtual ~SmushChannel(); - virtual bool appendData(Chunk &b, int32 size) = 0; + virtual bool appendData(Common::SeekableReadStream &b, int32 size) = 0; virtual bool setParameters(int32, int32, int32, int32, int32) = 0; virtual bool checkParameters(int32, int32, int32, int32, int32) = 0; virtual bool isTerminated() const = 0; @@ -83,7 +84,7 @@ public: bool isTerminated() const; bool setParameters(int32 duration, int32 flags, int32 vol1, int32 vol2, int32 index); bool checkParameters(int32 index, int32 duration, int32 flags, int32 vol1, int32 vol2); - bool appendData(Chunk &b, int32 size); + bool appendData(Common::SeekableReadStream &b, int32 size); byte *getSoundData(); int32 getRate() { return 22050; } bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) { @@ -105,7 +106,7 @@ private: protected: void decode(); - bool handleMap(Chunk &c); + bool handleMap(byte *data); bool handleSubTags(int32 &offset); public: @@ -113,7 +114,7 @@ public: bool isTerminated() const; bool setParameters(int32 nbframes, int32 size, int32 track_flags, int32 unk1, int32); bool checkParameters(int32 index, int32 nbframes, int32 size, int32 track_flags, int32 unk1); - bool appendData(Chunk &b, int32 size); + bool appendData(Common::SeekableReadStream &b, int32 size); byte *getSoundData(); int32 getRate() { return _rate; } bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) { diff --git a/engines/scumm/smush/chunk.cpp b/engines/scumm/smush/chunk.cpp deleted file mode 100644 index 5e6f05b3e4..0000000000 --- a/engines/scumm/smush/chunk.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* 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. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * 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. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - - -#include "scumm/smush/chunk.h" -#include "scumm/scumm.h" -#include "scumm/file.h" - -#include "common/file.h" -#include "common/str.h" -#include "common/util.h" - -namespace Scumm { - -BaseChunk::BaseChunk() : - _type(0), - _size(0), - _curPos(0), - _name("") { -} - -bool BaseChunk::eos() const { - return _curPos >= _size; -} - -uint32 BaseChunk::pos() const { - return _curPos; -} - -Chunk::type BaseChunk::getType() const { - return _type; -} - -uint32 BaseChunk::size() const { - return _size; -} - -void BaseChunk::seek(int32 delta, int dir) { - switch (dir) { - case SEEK_CUR: - _curPos += delta; - break; - case SEEK_SET: - if (delta < 0) - error("invalid seek request"); - _curPos = (uint32)delta; - break; - case SEEK_END: - if (delta > 0 || _size < (uint32)-delta) - error("invalid seek request"); - _curPos = (uint32)(_size + delta); - break; - default: - break; - } - - if (_curPos > _size) { - // It may happen that user misused our SAN compression tool - // and ignored FLU index for videos which are used by INSANE. - // This will lead to incorrect seek requests - // - // In fact it may happen only within INSANE, so do not even check for it - warning("Looks like you compressed file %s in wrong way. It has FLU index which was not updated", _name.c_str()); - error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta); - } -} - -FileChunk::FileChunk(BaseScummFile *data, int offset) { - _data = data; - _deleteData = false; - - _data->seek(offset, SEEK_SET); - _type = _data->readUint32BE(); - _size = _data->readUint32BE(); - _offset = _data->pos(); - _curPos = 0; -} - -FileChunk::FileChunk(const Common::String &name, int offset) { - _data = new ScummFile(); - _deleteData = true; - if (!g_scumm->openFile(*_data, name)) - error("FileChunk: Unable to open file %s", name.c_str()); - - _data->seek(offset, SEEK_SET); - _type = _data->readUint32BE(); - _size = _data->readUint32BE(); - _offset = _data->pos(); - _curPos = 0; - _name = name; -} - -FileChunk::~FileChunk() { - if (_deleteData) - delete _data; -} - -Chunk *FileChunk::subBlock() { - FileChunk *ptr = new FileChunk(_data, _offset + _curPos); - skip(sizeof(Chunk::type) + sizeof(uint32) + ptr->size()); - return ptr; -} - -void FileChunk::reseek() { - _data->seek(_offset + _curPos, SEEK_SET); -} - -uint32 FileChunk::read(void *buffer, uint32 dataSize) { - if (dataSize <= 0 || (_curPos + dataSize) > _size) - error("invalid buffer read request"); - - dataSize = _data->read(buffer, dataSize); - _curPos += dataSize; - - return dataSize; -} - -MemoryChunk::MemoryChunk(byte *data) { - if (data == 0) - error("Chunk() called with NULL pointer"); - - _type = (Chunk::type)READ_BE_UINT32(data); - _size = READ_BE_UINT32(data + 4); - _data = data + sizeof(Chunk::type) + sizeof(uint32); - _curPos = 0; -} - -Chunk *MemoryChunk::subBlock() { - MemoryChunk *ptr = new MemoryChunk(_data + _curPos); - skip(sizeof(Chunk::type) + sizeof(uint32) + ptr->size()); - return ptr; -} - -void MemoryChunk::reseek() { -} - -uint32 MemoryChunk::read(void *buffer, uint32 dataSize) { - if (dataSize <= 0 || (_curPos + dataSize) > _size) - error("invalid buffer read request"); - - memcpy(buffer, _data + _curPos, dataSize); - _curPos += dataSize; - return dataSize; -} - -} // End of namespace Scumm diff --git a/engines/scumm/smush/chunk.h b/engines/scumm/smush/chunk.h deleted file mode 100644 index ca4a3cdd99..0000000000 --- a/engines/scumm/smush/chunk.h +++ /dev/null @@ -1,92 +0,0 @@ -/* 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. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * 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. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef SCUMM_SMUSH_CHUNK_H -#define SCUMM_SMUSH_CHUNK_H - -#include "common/scummsys.h" -#include "common/str.h" -#include "common/stream.h" - -namespace Scumm { - -class BaseScummFile; - -class Chunk : public Common::SeekableReadStream { -public: - typedef uint32 type; - - virtual type getType() const = 0; - virtual Chunk *subBlock() = 0; - virtual void reseek() = 0; -}; - -// Common functionality for concrete chunks (FileChunk, MemoryChunk) -class BaseChunk : public Chunk { -protected: - Chunk::type _type; - uint32 _size; - uint32 _curPos; - Common::String _name; - - BaseChunk(); - -public: - Chunk::type getType() const; - uint32 size() const; - bool eos() const; - uint32 pos() const; - void seek(int32 delta, int dir); -}; - -class FileChunk : public BaseChunk { -private: - BaseScummFile *_data; - bool _deleteData; - uint32 _offset; - - FileChunk(BaseScummFile *data, int offset); -public: - FileChunk(const Common::String &name, int offset = 0); - virtual ~FileChunk(); - Chunk *subBlock(); - void reseek(); - uint32 read(void *buffer, uint32 size); -}; - -class MemoryChunk : public BaseChunk { -private: - byte *_data; - -public: - MemoryChunk(byte *data); - Chunk *subBlock(); - void reseek(); - uint32 read(void *buffer, uint32 size); -}; - -} // End of namespace Scumm - -#endif diff --git a/engines/scumm/smush/imuse_channel.cpp b/engines/scumm/smush/imuse_channel.cpp index 822f32a896..fd34a8f60d 100644 --- a/engines/scumm/smush/imuse_channel.cpp +++ b/engines/scumm/smush/imuse_channel.cpp @@ -29,7 +29,6 @@ #include "scumm/scumm.h" // For DEBUG_SMUSH #include "scumm/util.h" #include "scumm/smush/channel.h" -#include "scumm/smush/chunk.h" namespace Scumm { @@ -60,10 +59,10 @@ bool ImuseChannel::checkParameters(int32 index, int32 nbframes, int32 size, int3 return true; } -bool ImuseChannel::appendData(Chunk &b, int32 size) { +bool ImuseChannel::appendData(Common::SeekableReadStream &b, int32 size) { if (_dataSize == -1) { assert(size > 8); - Chunk::type imus_type = b.readUint32BE(); + uint32 imus_type = b.readUint32BE(); /*uint32 imus_size =*/ b.readUint32BE(); if (imus_type != MKID_BE('iMUS')) error("Invalid Chunk for imuse_channel"); @@ -104,35 +103,45 @@ bool ImuseChannel::appendData(Chunk &b, int32 size) { return true; } -bool ImuseChannel::handleMap(Chunk &map) { - while (!map.eos()) { - Chunk *sub = map.subBlock(); - switch (sub->getType()) { +bool ImuseChannel::handleMap(byte *data) { + // Read the chunk size & skip over the chunk header + int32 size = READ_BE_UINT32(data + 4); + data += 8; + + while (size > 0) { + uint32 subType = READ_BE_UINT32(data); + int32 subSize = READ_BE_UINT32(data + 4); + data += 8; + size -= 8; + + switch (subType) { case MKID_BE('FRMT'): - if (sub->size() != 20) + if (subSize != 20) error("invalid size for FRMT Chunk"); - /*uint32 imuse_start =*/ sub->readUint32BE(); - sub->skip(4); - _bitsize = sub->readUint32BE(); - _rate = sub->readUint32BE(); - _channels = sub->readUint32BE(); + //uint32 imuse_start = READ_BE_UINT32(data); + //uint32 unk = READ_BE_UINT32(data+4); + _bitsize = READ_BE_UINT32(data+8); + _rate = READ_BE_UINT32(data+12); + _channels = READ_BE_UINT32(data+16); assert(_channels == 1 || _channels == 2); break; case MKID_BE('TEXT'): // Ignore this break; case MKID_BE('REGN'): - if (sub->size() != 8) + if (subSize != 8) error("invalid size for REGN Chunk"); break; case MKID_BE('STOP'): - if (sub->size() != 4) + if (subSize != 4) error("invalid size for STOP Chunk"); break; default: - error("Unknown iMUS subChunk found : %s, %d", tag2str(sub->getType()), sub->size()); + error("Unknown iMUS subChunk found : %s, %d", tag2str(subType), subSize); } - delete sub; + + data += subSize; + size -= subSize; } return true; } @@ -187,15 +196,14 @@ void ImuseChannel::decode() { bool ImuseChannel::handleSubTags(int32 &offset) { if (_tbufferSize - offset >= 8) { - Chunk::type type = READ_BE_UINT32(_tbuffer + offset); + uint32 type = READ_BE_UINT32(_tbuffer + offset); uint32 size = READ_BE_UINT32(_tbuffer + offset + 4); uint32 available_size = _tbufferSize - offset; switch (type) { case MKID_BE('MAP '): _inData = false; if (available_size >= (size + 8)) { - MemoryChunk c((byte *)_tbuffer + offset); - handleMap(c); + handleMap((byte *)_tbuffer + offset); } break; case MKID_BE('DATA'): diff --git a/engines/scumm/smush/saud_channel.cpp b/engines/scumm/smush/saud_channel.cpp index 2fe34efe29..a56afa8f44 100644 --- a/engines/scumm/smush/saud_channel.cpp +++ b/engines/scumm/smush/saud_channel.cpp @@ -25,10 +25,10 @@ #include "common/endian.h" +#include "common/stream.h" #include "scumm/util.h" #include "scumm/smush/channel.h" -#include "scumm/smush/chunk.h" namespace Scumm { @@ -45,7 +45,7 @@ bool SaudChannel::isTerminated() const { bool SaudChannel::handleSubTags(int32 &offset) { if (_tbufferSize - offset >= 8) { - Chunk::type type = READ_BE_UINT32(_tbuffer + offset); + uint32 type = READ_BE_UINT32(_tbuffer + offset); uint32 size = READ_BE_UINT32(_tbuffer + offset + 4); uint32 available_size = _tbufferSize - offset; @@ -53,9 +53,9 @@ bool SaudChannel::handleSubTags(int32 &offset) { case MKID_BE('STRK'): _inData = false; if (available_size >= (size + 8)) { - MemoryChunk c((byte *)_tbuffer + offset); - if (c.size() != 14 && c.size() != 10) { - error("STRK has an invalid size : %d", c.size()); + int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4); + if (subSize != 14 && subSize != 10) { + error("STRK has an invalid size : %d", subSize); } } else return false; @@ -63,7 +63,9 @@ bool SaudChannel::handleSubTags(int32 &offset) { case MKID_BE('SMRK'): _inData = false; if (available_size >= (size + 8)) { - MemoryChunk c((byte *)_tbuffer + offset); + int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4); + if (subSize != 0) + error("SMRK has an invalid size : %d", subSize); _markReached = true; } else return false; @@ -71,9 +73,9 @@ bool SaudChannel::handleSubTags(int32 &offset) { case MKID_BE('SHDR'): _inData = false; if (available_size >= (size + 8)) { - MemoryChunk c((byte *)_tbuffer + offset); - if (c.size() != 4) - error("SHDR has an invalid size : %d", c.size()); + int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4); + if (subSize != 4) + error("SHDR has an invalid size : %d", subSize); } else return false; break; @@ -119,10 +121,10 @@ bool SaudChannel::checkParameters(int32 index, int32 nb, int32 flags, int32 volu return true; } -bool SaudChannel::appendData(Chunk &b, int32 size) { +bool SaudChannel::appendData(Common::SeekableReadStream &b, int32 size) { if (_dataSize == -1) { assert(size > 8); - Chunk::type saud_type = b.readUint32BE(); + uint32 saud_type = b.readUint32BE(); /*uint32 saud_size =*/ b.readUint32BE(); if (saud_type != MKID_BE('SAUD')) error("Invalid Chunk for SaudChannel : %X", saud_type); diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp index 494357a90c..6b79b7e2c4 100644 --- a/engines/scumm/smush/smush_player.cpp +++ b/engines/scumm/smush/smush_player.cpp @@ -23,8 +23,6 @@ * */ - - #include "engines/engine.h" #include "common/config-manager.h" @@ -42,7 +40,6 @@ #include "scumm/sound.h" #include "scumm/util.h" #include "scumm/smush/channel.h" -#include "scumm/smush/chunk.h" #include "scumm/smush/codec37.h" #include "scumm/smush/codec47.h" #include "scumm/smush/smush_font.h" @@ -55,10 +52,6 @@ #include "sound/vorbis.h" #include "sound/mp3.h" -#ifdef DUMP_SMUSH_FRAMES -#include <png.h> -#endif - #include "common/zlib.h" namespace Scumm { @@ -212,10 +205,6 @@ static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_enc void SmushPlayer::timerCallback() { parseNextFrame(); -#ifdef _WIN32_WCE - _inTimer = true; - _inTimerCount++; -#endif } SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) { @@ -252,11 +241,6 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) { _paused = false; _pauseStartTime = 0; _pauseTime = 0; -#ifdef _WIN32_WCE - _inTimer = false; - _inTimerCount = 0; - _inTimerCountRedraw = ConfMan.getInt("Smush_force_redraw"); -#endif } SmushPlayer::~SmushPlayer() { @@ -328,16 +312,7 @@ void SmushPlayer::release() { _codec47 = 0; } -void SmushPlayer::checkBlock(const Chunk &b, Chunk::type type_expected, uint32 min_size) { - if (type_expected != b.getType()) { - error("Chunk type is different from expected : %x != %x", b.getType(), type_expected); - } - if (min_size > b.size()) { - error("Chunk size is inferior than minimum required size : %d < %d", b.size(), min_size); - } -} - -void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Chunk &b, int32 size) { +void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Common::SeekableReadStream &b, int32 size) { debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundBuffer(%d, %d)", track_id, index); // if ((flags & 128) == 128) { // return; @@ -360,8 +335,7 @@ void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frame c->appendData(b, size); } -void SmushPlayer::handleSoundFrame(Chunk &b) { - checkBlock(b, MKID_BE('PSAD')); +void SmushPlayer::handleSoundFrame(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundFrame()"); int32 track_id = b.readUint16LE(); @@ -373,28 +347,28 @@ void SmushPlayer::handleSoundFrame(Chunk &b) { if (index == 0) { debugC(DEBUG_SMUSH, "track_id:%d, max_frames:%d, flags:%d, vol:%d, pan:%d", track_id, max_frames, flags, vol, pan); } - int32 size = b.size() - 10; + int32 size = subSize - 10; handleSoundBuffer(track_id, index, max_frames, flags, vol, pan, b, size); } -void SmushPlayer::handleStore(Chunk &b) { +void SmushPlayer::handleStore(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleStore()"); - checkBlock(b, MKID_BE('STOR'), 4); + assert(subSize >= 4); _storeFrame = true; } -void SmushPlayer::handleFetch(Chunk &b) { +void SmushPlayer::handleFetch(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleFetch()"); - checkBlock(b, MKID_BE('FTCH'), 6); + assert(subSize >= 6); if (_frameBuffer != NULL) { memcpy(_dst, _frameBuffer, _width * _height); } } -void SmushPlayer::handleIACT(Chunk &b) { - checkBlock(b, MKID_BE('IACT'), 8); +void SmushPlayer::handleIACT(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::IACT()"); + assert(subSize >= 8); int code = b.readUint16LE(); int flags = b.readUint16LE(); @@ -415,7 +389,7 @@ void SmushPlayer::handleIACT(Chunk &b) { int index = b.readUint16LE(); int nbframes = b.readUint16LE(); int32 size = b.readUint32LE(); - int32 bsize = b.size() - 18; + int32 bsize = subSize - 18; if (_vm->_game.id != GID_CMI) { int32 track = track_id; @@ -519,7 +493,7 @@ void SmushPlayer::handleIACT(Chunk &b) { } } -void SmushPlayer::handleTextResource(Chunk &b) { +void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &b) { int pos_x = b.readSint16LE(); int pos_y = b.readSint16LE(); int flags = b.readSint16LE(); @@ -531,10 +505,10 @@ void SmushPlayer::handleTextResource(Chunk &b) { const char *str; char *string = NULL, *string2 = NULL; - if (b.getType() == MKID_BE('TEXT')) { - string = (char *)malloc(b.size() - 16); + if (subType == MKID_BE('TEXT')) { + string = (char *)malloc(subSize - 16); str = string; - b.read(string, b.size() - 16); + b.read(string, subSize - 16); } else { int string_id = b.readUint16LE(); if (!_strings) @@ -702,7 +676,7 @@ bool SmushPlayer::readString(const char *file) { return false; } -void SmushPlayer::readPalette(byte *out, Chunk &in) { +void SmushPlayer::readPalette(byte *out, Common::SeekableReadStream &in) { in.read(out, 0x300); } @@ -711,11 +685,10 @@ static byte delta_color(byte org_color, int16 delta_color) { return CLIP(t, 0, 255); } -void SmushPlayer::handleDeltaPalette(Chunk &b) { - checkBlock(b, MKID_BE('XPAL')); +void SmushPlayer::handleDeltaPalette(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleDeltaPalette()"); - if (b.size() == 0x300 * 3 + 4) { + if (subSize == 0x300 * 3 + 4) { b.readUint16LE(); b.readUint16LE(); @@ -725,7 +698,7 @@ void SmushPlayer::handleDeltaPalette(Chunk &b) { } readPalette(_pal, b); setDirtyColors(0, 255); - } else if (b.size() == 6) { + } else if (subSize == 6) { b.readUint16LE(); b.readUint16LE(); @@ -740,9 +713,9 @@ void SmushPlayer::handleDeltaPalette(Chunk &b) { } } -void SmushPlayer::handleNewPalette(Chunk &b) { - checkBlock(b, MKID_BE('NPAL'), 0x300); +void SmushPlayer::handleNewPalette(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleNewPalette()"); + assert(subSize >= 0x300); if (_skipPalette) return; @@ -805,21 +778,20 @@ void SmushPlayer::decodeFrameObject(int codec, const uint8 *src, int left, int t } #ifdef USE_ZLIB -void SmushPlayer::handleZlibFrameObject(Chunk &b) { +void SmushPlayer::handleZlibFrameObject(int32 subSize, Common::SeekableReadStream &b) { if (_skipNext) { _skipNext = false; return; } - int32 chunkSize = b.size(); + int32 chunkSize = subSize; byte *chunkBuffer = (byte *)malloc(chunkSize); assert(chunkBuffer); b.read(chunkBuffer, chunkSize); unsigned long decompressedSize = READ_BE_UINT32(chunkBuffer); byte *fobjBuffer = (byte *)malloc(decompressedSize); - int result = Common::uncompress(fobjBuffer, &decompressedSize, chunkBuffer + 4, chunkSize - 4); - if (result != Common::ZLIB_OK) + if (!Common::uncompress(fobjBuffer, &decompressedSize, chunkBuffer + 4, chunkSize - 4)) error("SmushPlayer::handleZlibFrameObject() Zlib uncompress error"); free(chunkBuffer); @@ -836,8 +808,8 @@ void SmushPlayer::handleZlibFrameObject(Chunk &b) { } #endif -void SmushPlayer::handleFrameObject(Chunk &b) { - checkBlock(b, MKID_BE('FOBJ'), 14); +void SmushPlayer::handleFrameObject(int32 subSize, Common::SeekableReadStream &b) { + assert(subSize >= 14); if (_skipNext) { _skipNext = false; return; @@ -852,7 +824,7 @@ void SmushPlayer::handleFrameObject(Chunk &b) { b.readUint16LE(); b.readUint16LE(); - int32 chunk_size = b.size() - 14; + int32 chunk_size = subSize - 14; byte *chunk_buffer = (byte *)malloc(chunk_size); assert(chunk_buffer); b.read(chunk_buffer, chunk_size); @@ -862,8 +834,7 @@ void SmushPlayer::handleFrameObject(Chunk &b) { free(chunk_buffer); } -void SmushPlayer::handleFrame(Chunk &b) { - checkBlock(b, MKID_BE('FRME')); +void SmushPlayer::handleFrame(int32 frameSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleFrame(%d)", _frame); _skipNext = false; @@ -871,54 +842,57 @@ void SmushPlayer::handleFrame(Chunk &b) { _vm->_insane->procPreRendering(); } - while (!b.eos()) { - Chunk *sub = b.subBlock(); - switch (sub->getType()) { + while (frameSize > 0) { + const uint32 subType = b.readUint32BE(); + const int32 subSize = b.readUint32BE(); + const int32 subOffset = b.pos(); + switch (subType) { case MKID_BE('NPAL'): - handleNewPalette(*sub); + handleNewPalette(subSize, b); break; case MKID_BE('FOBJ'): - handleFrameObject(*sub); + handleFrameObject(subSize, b); break; #ifdef USE_ZLIB case MKID_BE('ZFOB'): - handleZlibFrameObject(*sub); + handleZlibFrameObject(subSize, b); break; #endif case MKID_BE('PSAD'): if (!_compressedFileMode) - handleSoundFrame(*sub); + handleSoundFrame(subSize, b); break; case MKID_BE('TRES'): - handleTextResource(*sub); + handleTextResource(subType, subSize, b); break; case MKID_BE('XPAL'): - handleDeltaPalette(*sub); + handleDeltaPalette(subSize, b); break; case MKID_BE('IACT'): - handleIACT(*sub); + handleIACT(subSize, b); break; case MKID_BE('STOR'): - handleStore(*sub); + handleStore(subSize, b); break; case MKID_BE('FTCH'): - handleFetch(*sub); + handleFetch(subSize, b); break; case MKID_BE('SKIP'): - _vm->_insane->procSKIP(*sub); + _vm->_insane->procSKIP(subSize, b); break; case MKID_BE('TEXT'): - handleTextResource(*sub); + handleTextResource(subType, subSize, b); break; default: - error("Unknown frame subChunk found : %s, %d", tag2str(sub->getType()), sub->size()); + error("Unknown frame subChunk found : %s, %d", tag2str(subType), subSize); } - b.reseek(); - if (sub->size() & 1) + frameSize -= subSize + 8; + b.seek(subOffset + subSize, SEEK_SET); + if (subSize & 1) { b.skip(1); - - delete sub; + frameSize--; + } } if (_insanity) { @@ -926,23 +900,16 @@ void SmushPlayer::handleFrame(Chunk &b) { } if (_width != 0 && _height != 0) { -#ifdef _WIN32_WCE - if (!_inTimer || _inTimerCount == _inTimerCountRedraw) { - updateScreen(); - _inTimerCount = 0; - } -#else updateScreen(); -#endif } _smixer->handleFrame(); _frame++; } -void SmushPlayer::handleAnimHeader(Chunk &b) { - checkBlock(b, MKID_BE('AHDR'), 0x300 + 6); +void SmushPlayer::handleAnimHeader(int32 subSize, Common::SeekableReadStream &b) { debugC(DEBUG_SMUSH, "SmushPlayer::handleAnimHeader()"); + assert(subSize >= 0x300 + 6); /* _version = */ b.readUint16LE(); _nbframes = b.readUint16LE(); @@ -1004,7 +971,6 @@ SmushFont *SmushPlayer::getFont(int font) { } void SmushPlayer::parseNextFrame() { - Chunk *sub; if (_seekPos >= 0) { if (_smixer) @@ -1012,15 +978,23 @@ void SmushPlayer::parseNextFrame() { if (_seekFile.size() > 0) { delete _base; - _base = new FileChunk(_seekFile); + + ScummFile *tmp = new ScummFile(); + if (!g_scumm->openFile(*tmp, _seekFile)) + error("SmushPlayer: Unable to open file %s", _seekFile.c_str()); + _base = tmp; + _base->readUint32BE(); + _base->readUint32BE(); if (_seekPos > 0) { assert(_seekPos > 8); // In this case we need to get palette and number of frames - sub = _base->subBlock(); - checkBlock(*sub, MKID_BE('AHDR')); - handleAnimHeader(*sub); - delete sub; + const uint32 subType = _base->readUint32BE(); + const int32 subSize = _base->readUint32BE(); + const int32 subOffset = _base->pos(); + assert(subType == MKID_BE('AHDR')); + handleAnimHeader(subSize, *_base); + _base->seek(subOffset + subSize, SEEK_SET); _middleAudio = true; _seekPos -= 8; @@ -1034,7 +1008,7 @@ void SmushPlayer::parseNextFrame() { _skipPalette = true; } - _base->seek(_seekPos, SEEK_SET); + _base->seek(_seekPos + 8, SEEK_SET); _frame = _seekFrame; _startFrame = _frame; _startTime = _vm->_system->getMillis(); @@ -1049,21 +1023,22 @@ void SmushPlayer::parseNextFrame() { return; } - sub = _base->subBlock(); + const uint32 subType = _base->readUint32BE(); + const int32 subSize = _base->readUint32BE(); + const int32 subOffset = _base->pos(); - switch (sub->getType()) { + switch (subType) { case MKID_BE('AHDR'): // FT INSANE may seek file to the beginning - handleAnimHeader(*sub); + handleAnimHeader(subSize, *_base); break; case MKID_BE('FRME'): - handleFrame(*sub); + handleFrame(subSize, *_base); break; default: - error("Unknown Chunk found at %x: %x, %d", _base->pos(), sub->getType(), sub->size()); + error("Unknown Chunk found at %x: %x, %d", subOffset, subType, subSize); } - delete sub; - _base->reseek(); + _base->seek(subOffset + subSize, SEEK_SET); if (_insanity) _vm->_sound->processSound(); @@ -1098,57 +1073,6 @@ void SmushPlayer::warpMouse(int x, int y, int buttons) { } void SmushPlayer::updateScreen() { -#ifdef DUMP_SMUSH_FRAMES - char fileName[100]; - // change path below for dump png files - sprintf(fileName, "/path/to/somethere/%s%04d.png", _vm->getBaseName(), _frame); - FILE *file = fopen(fileName, "wb"); - if (file == NULL) - error("can't open file for writing png"); - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (png_ptr == NULL) { - fclose(file); - error("can't write png header"); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - fclose(file); - error("can't create png info struct"); - } - if (setjmp(png_ptr->jmpbuf)) { - fclose(file); - error("png jmpbuf error"); - } - - png_init_io(png_ptr, file); - - png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color)); - for (int i = 0; i != 256; ++i) { - (palette + i)->red = _pal[i * 3 + 0]; - (palette + i)->green = _pal[i * 3 + 1]; - (palette + i)->blue = _pal[i * 3 + 2]; - } - - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - - png_write_info(png_ptr, info_ptr); - png_set_flush(png_ptr, 10); - - png_bytep row_pointers[480]; - for (int y = 0 ; y < _height ; y++) - row_pointers[y] = (png_byte *) (_dst + y * _width); - png_write_image(png_ptr, row_pointers); - png_write_end(png_ptr, info_ptr); - png_free(png_ptr, palette); - - fclose(file); - png_destroy_write_struct(&png_ptr, &info_ptr); -#endif - uint32 end_time, start_time = _vm->_system->getMillis(); _updateNeeded = true; end_time = _vm->_system->getMillis(); @@ -1326,14 +1250,10 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st _vm->_system->updateScreen(); _updateNeeded = false; } -#ifdef _WIN32_WCE - _inTimer = false; - _inTimerCount = 0; -#endif } if (_endOfFile) break; - if (_vm->_quit || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) { + if (_vm->quit() || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) { _smixer->stop(); _vm->_mixer->stopHandle(_compressedFileSoundHandle); _vm->_mixer->stopHandle(_IACTchannel); diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h index 413a5895d3..2e2996009c 100644 --- a/engines/scumm/smush/smush_player.h +++ b/engines/scumm/smush/smush_player.h @@ -27,7 +27,6 @@ #define SCUMM_SMUSH_PLAYER_H #include "common/util.h" -#include "scumm/smush/chunk.h" #include "scumm/sound.h" namespace Scumm { @@ -51,7 +50,7 @@ private: StringResource *_strings; Codec37Decoder *_codec37; Codec47Decoder *_codec47; - FileChunk *_base; + Common::SeekableReadStream *_base; byte *_frameBuffer; byte *_specialBuffer; @@ -84,11 +83,6 @@ private: bool _insanity; bool _middleAudio; bool _skipPalette; -#ifdef _WIN32_WCE - bool _inTimer; - int16 _inTimerCount; - int16 _inTimerCountRedraw; -#endif public: SmushPlayer(ScummEngine_v7 *scumm); @@ -126,22 +120,21 @@ private: bool readString(const char *file); void decodeFrameObject(int codec, const uint8 *src, int left, int top, int width, int height); - void checkBlock(const Chunk &, Chunk::type, uint32 = 0); - void handleAnimHeader(Chunk &); - void handleFrame(Chunk &); - void handleNewPalette(Chunk &); + void handleAnimHeader(int32 subSize, Common::SeekableReadStream &); + void handleFrame(int32 frameSize, Common::SeekableReadStream &); + void handleNewPalette(int32 subSize, Common::SeekableReadStream &); #ifdef USE_ZLIB - void handleZlibFrameObject(Chunk &b); + void handleZlibFrameObject(int32 subSize, Common::SeekableReadStream &b); #endif - void handleFrameObject(Chunk &); - void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32); - void handleSoundFrame(Chunk &); - void handleStore(Chunk &); - void handleFetch(Chunk &); - void handleIACT(Chunk &); - void handleTextResource(Chunk &); - void handleDeltaPalette(Chunk &); - void readPalette(byte *, Chunk &); + void handleFrameObject(int32 subSize, Common::SeekableReadStream &); + void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Common::SeekableReadStream &, int32); + void handleSoundFrame(int32 subSize, Common::SeekableReadStream &); + void handleStore(int32 subSize, Common::SeekableReadStream &); + void handleFetch(int32 subSize, Common::SeekableReadStream &); + void handleIACT(int32 subSize, Common::SeekableReadStream &); + void handleTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &); + void handleDeltaPalette(int32 subSize, Common::SeekableReadStream &); + void readPalette(byte *, Common::SeekableReadStream &); void timerCallback(); }; diff --git a/engines/scumm/thumbnail.cpp b/engines/scumm/thumbnail.cpp deleted file mode 100644 index 40f1ee48e5..0000000000 --- a/engines/scumm/thumbnail.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* 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. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed file 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. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - - -#include "common/system.h" -#include "common/savefile.h" -#include "graphics/scaler.h" -#include "scumm/scumm.h" - -namespace Scumm { - -#define THMB_VERSION 1 - -struct ThumbnailHeader { - uint32 type; - uint32 size; - byte version; - uint16 width, height; - byte bpp; -}; - -#define ThumbnailHeaderSize (4+4+1+2+2+1) - -inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) { - r = (((color >> 11) & 0x1F) << 3); - g = (((color >> 5) & 0x3F) << 2); - b = ((color&0x1F) << 3); -} - -Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) { - ThumbnailHeader header; - - header.type = file->readUint32BE(); - // We also accept the bad 'BMHT' header here, for the sake of compatibility - // with some older savegames which were written incorrectly due to a bug in - // ScummVM which wrote the thumb header type incorrectly on LE systems. - if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) - return 0; - - header.size = file->readUint32BE(); - header.version = file->readByte(); - - if (header.version > THMB_VERSION) { - file->skip(header.size - 9); - warning("Loading a newer thumbnail version"); - return 0; - } - - header.width = file->readUint16BE(); - header.height = file->readUint16BE(); - header.bpp = file->readByte(); - - // TODO: support other bpp values than 2 - if (header.bpp != 2) { - file->skip(header.size - 14); - return 0; - } - - Graphics::Surface *thumb = new Graphics::Surface(); - thumb->create(header.width, header.height, sizeof(OverlayColor)); - - OverlayColor* pixels = (OverlayColor *)thumb->pixels; - - for (int y = 0; y < thumb->h; ++y) { - for (int x = 0; x < thumb->w; ++x) { - uint8 r, g, b; - colorToRGB(file->readUint16BE(), r, g, b); - - // converting to current OSystem Color - *pixels++ = _system->RGBToColor(r, g, b); - } - } - - return thumb; -} - -void ScummEngine::saveThumbnail(Common::OutSaveFile *file) { - Graphics::Surface thumb; - -#if !defined(__DS__) - if (!createThumbnailFromScreen(&thumb)) -#endif - thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16)); - - ThumbnailHeader header; - header.type = MKID_BE('THMB'); - header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; - header.version = THMB_VERSION; - header.width = thumb.w; - header.height = thumb.h; - header.bpp = thumb.bytesPerPixel; - - file->writeUint32BE(header.type); - file->writeUint32BE(header.size); - file->writeByte(header.version); - file->writeUint16BE(header.width); - file->writeUint16BE(header.height); - file->writeByte(header.bpp); - - // TODO: for later this shouldn't be casted to uint16... - uint16* pixels = (uint16 *)thumb.pixels; - for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels) - file->writeUint16BE(*pixels); - - thumb.free(); -} - -} // end of namespace Scumm diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp index 9d6b58704d..8699c893e4 100644 --- a/engines/sky/control.cpp +++ b/engines/sky/control.cpp @@ -238,13 +238,17 @@ void Control::removePanel(void) { free(_sprites.slide2); free(_sprites.slode); free(_sprites.slode2); free(_sprites.musicBodge); delete _controlPanel; delete _exitButton; - delete _slide; delete _slide2; - delete _slode; delete _restorePanButton; + delete _slide; delete _slide2; + delete _slode; delete _restorePanButton; + delete _savePanel; delete _saveButton; + delete _downFastButton; delete _downSlowButton; + delete _upFastButton; delete _upSlowButton; + delete _quitButton; delete _autoSaveButton; delete _savePanButton; delete _dosPanButton; delete _restartPanButton; delete _fxPanButton; delete _musicPanButton; delete _bodge; - delete _yesNo; delete _text; - delete _statusBar; delete _restoreButton; + delete _yesNo; delete _text; + delete _statusBar; delete _restoreButton; if (_textSprite) { free(_textSprite); @@ -492,7 +496,7 @@ void Control::doControlPanel(void) { _curButtonText = 0; uint16 clickRes = 0; - while (!quitPanel && !SkyEngine::_systemVars.quitGame) { + while (!quitPanel && !g_engine->quit()) { _text->drawToScreen(WITH_MASK); _system->updateScreen(); _mouseClicked = false; @@ -524,7 +528,7 @@ void Control::doControlPanel(void) { } memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT); _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT); - if (!SkyEngine::_systemVars.quitGame) + if (!g_engine->quit()) _system->updateScreen(); _skyScreen->forceRefresh(); _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette)); @@ -603,7 +607,7 @@ uint16 Control::handleClick(ConResource *pButton) { case QUIT_TO_DOS: animClick(pButton); if (getYesNo(quitDos)) - SkyEngine::_systemVars.quitGame = true; + g_engine->quitGame(); return 0; default: error("Control::handleClick: unknown routine: %X",pButton->_onClick); @@ -875,7 +879,7 @@ uint16 Control::saveRestorePanel(bool allowSave) { bool refreshNames = true; bool refreshAll = true; uint16 clickRes = 0; - while (!quitPanel && !SkyEngine::_systemVars.quitGame) { + while (!quitPanel && !g_engine->quit()) { clickRes = 0; if (refreshNames || refreshAll) { if (refreshAll) { @@ -1546,9 +1550,6 @@ void Control::delay(unsigned int amount) { case Common::EVENT_WHEELDOWN: _mouseWheel = 1; break; - case Common::EVENT_QUIT: - SkyEngine::_systemVars.quitGame = true; - break; default: break; } diff --git a/engines/sky/intro.cpp b/engines/sky/intro.cpp index 024360561c..86e26309c9 100644 --- a/engines/sky/intro.cpp +++ b/engines/sky/intro.cpp @@ -636,14 +636,10 @@ Intro::Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *t _textBuf = (uint8*)malloc(10000); _saveBuf = (uint8*)malloc(10000); _bgBuf = NULL; - _quitProg = false; _relDelay = 0; } Intro::~Intro(void) { - - _mixer->stopAll(); - _skyScreen->stopSequence(); if (_textBuf) free(_textBuf); if (_saveBuf) @@ -912,8 +908,7 @@ bool Intro::escDelay(uint32 msecs) { if (event.type == Common::EVENT_KEYDOWN) { if (event.kbd.keycode == Common::KEYCODE_ESCAPE) return false; - } else if (event.type == Common::EVENT_QUIT) { - _quitProg = true; + } else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL) { return false; } } diff --git a/engines/sky/intro.h b/engines/sky/intro.h index 4a54fb8dd3..796bcf7e36 100644 --- a/engines/sky/intro.h +++ b/engines/sky/intro.h @@ -43,7 +43,6 @@ public: Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *text, Audio::Mixer *mixer, OSystem *system); ~Intro(void); bool doIntro(bool floppyIntro); - bool _quitProg; private: static uint16 _mainIntroSeq[]; static uint16 _floppyIntroSeq[]; diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp index c6c6c34c4d..9f13bf9bee 100644 --- a/engines/sky/logic.cpp +++ b/engines/sky/logic.cpp @@ -2490,7 +2490,7 @@ bool Logic::fnFadeUp(uint32 a, uint32 b, uint32 c) { } bool Logic::fnQuitToDos(uint32 a, uint32 b, uint32 c) { - SkyEngine::_systemVars.quitGame = true; + g_engine->quitGame(); return false; } diff --git a/engines/sky/mouse.cpp b/engines/sky/mouse.cpp index b3be8b4f36..1fc9e47539 100644 --- a/engines/sky/mouse.cpp +++ b/engines/sky/mouse.cpp @@ -180,7 +180,6 @@ void Mouse::waitMouseNotPressed(int minDelay) { while (mousePressed || _system->getMillis() < now + minDelay) { if (eventMan->shouldQuit()) { - SkyEngine::_systemVars.quitGame = true; minDelay = 0; mousePressed = false; } diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp index d87ed06fef..0900ba5617 100644 --- a/engines/sky/sky.cpp +++ b/engines/sky/sky.cpp @@ -110,9 +110,10 @@ public: virtual const char *getName() const; virtual const char *getCopyright() const; + virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual GameDescriptor findGame(const char *gameid) const; - virtual GameList detectGames(const FSList &fslist) const; + virtual GameList detectGames(const Common::FSList &fslist) const; virtual PluginError createInstance(OSystem *syst, Engine **engine) const; @@ -127,6 +128,13 @@ const char *SkyMetaEngine::getCopyright() const { return "Beneath a Steel Sky (C) Revolution"; } +bool SkyMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad); +} + GameList SkyMetaEngine::getSupportedGames() const { GameList games; games.push_back(skySetting); @@ -139,7 +147,7 @@ GameDescriptor SkyMetaEngine::findGame(const char *gameid) const { return GameDescriptor(); } -GameList SkyMetaEngine::detectGames(const FSList &fslist) const { +GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; bool hasSkyDsk = false; bool hasSkyDnr = false; @@ -147,7 +155,7 @@ GameList SkyMetaEngine::detectGames(const FSList &fslist) const { int dataDiskSize = -1; // Iterate over all files in the given directory - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (!file->isDirectory()) { const char *fileName = file->getName().c_str(); @@ -257,7 +265,7 @@ namespace Sky { void *SkyEngine::_itemList[300]; -SystemVars SkyEngine::_systemVars = {0, 0, 0, 0, 4316, 0, 0, false, false, false }; +SystemVars SkyEngine::_systemVars = {0, 0, 0, 0, 4316, 0, 0, false, false }; SkyEngine::SkyEngine(OSystem *syst) : Engine(syst), _fastMode(0), _debugger(0) { @@ -277,6 +285,8 @@ SkyEngine::~SkyEngine() { delete _skyDisk; delete _skyControl; delete _skyCompact; + if (_skyIntro) + delete _skyIntro; for (int i = 0; i < 300; i++) if (_itemList[i]) @@ -288,7 +298,6 @@ GUI::Debugger *SkyEngine::getDebugger() { } void SkyEngine::initVirgin() { - _skyScreen->setPalette(60111); _skyScreen->showScreen(60110); } @@ -340,25 +349,23 @@ void SkyEngine::handleKey(void) { int SkyEngine::go() { - _systemVars.quitGame = false; - _keyPressed.reset(); uint16 result = 0; - if (ConfMan.hasKey("save_slot") && ConfMan.getInt("save_slot") >= 0) - result = _skyControl->quickXRestore(ConfMan.getInt("save_slot")); + if (ConfMan.hasKey("save_slot")) { + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0 && saveSlot <= 999) + result = _skyControl->quickXRestore(ConfMan.getInt("save_slot")); + } if (result != GAME_RESTORED) { bool introSkipped = false; if (_systemVars.gameVersion > 267) { // don't do intro for floppydemos _skyIntro = new Intro(_skyDisk, _skyScreen, _skyMusic, _skySound, _skyText, _mixer, _system); introSkipped = !_skyIntro->doIntro(_floppyIntro); - _systemVars.quitGame = _skyIntro->_quitProg; - - delete _skyIntro; } - if (!_systemVars.quitGame) { + if (!quit()) { _skyLogic->initScreen0(); if (introSkipped) _skyControl->restartGame(); @@ -368,7 +375,7 @@ int SkyEngine::go() { _lastSaveTime = _system->getMillis(); uint32 delayCount = _system->getMillis(); - while (!_systemVars.quitGame) { + while (!quit()) { if (_debugger->isAttached()) _debugger->onFrame(); @@ -440,7 +447,7 @@ int SkyEngine::init() { _floppyIntro = ConfMan.getBool("alt_intro"); _skyDisk = new Disk(); - _skySound = new Sound(_mixer, _skyDisk, ConfMan.getInt("sfx_volume")); + _skySound = new Sound(_mixer, _skyDisk, Audio::Mixer::kMaxChannelVolume); _systemVars.gameVersion = _skyDisk->determineGameVersion(); @@ -475,6 +482,7 @@ int SkyEngine::init() { _systemVars.systemFlags |= SF_PLAY_VOCS; _systemVars.gameSpeed = 50; + _skyIntro = 0; _skyCompact = new SkyCompact(); _skyText = new Text(_skyDisk, _skyCompact); _skyMouse = new Mouse(_system, _skyDisk, _skyCompact); @@ -615,9 +623,6 @@ void SkyEngine::delay(int32 amount) { _skyMouse->mouseMoved(event.mouse.x, event.mouse.y); _skyMouse->buttonPressed(1); break; - case Common::EVENT_QUIT: - _systemVars.quitGame = true; - break; default: break; } diff --git a/engines/sky/sky.h b/engines/sky/sky.h index b5d1701930..47aebaba77 100644 --- a/engines/sky/sky.h +++ b/engines/sky/sky.h @@ -41,7 +41,6 @@ struct SystemVars { uint16 gameSpeed; uint16 currentMusic; bool pastIntro; - bool quitGame; bool paused; }; diff --git a/engines/sky/skydefs.h b/engines/sky/skydefs.h index f4be91b3d1..f68c0f826b 100644 --- a/engines/sky/skydefs.h +++ b/engines/sky/skydefs.h @@ -2023,14 +2023,14 @@ namespace Sky { #define DISQ_13 26624 #define DISQ_14 28672 #define DISQ_15 30720 -#define T0 0 -#define T1 4096 -#define T2 8192 -#define T3 12288 -#define T4 16384 -#define T5 20480 -#define T6 24576 -#define T7 28672 +//#define T0 0 +//#define T1 4096 +//#define T2 8192 +//#define T3 12288 +//#define T4 16384 +//#define T5 20480 +//#define T6 24576 +//#define T7 28672 #define UP 0 #define DOWN 1 #define LEFT 2 diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 2bb027ddb4..3e15429e44 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -189,7 +189,7 @@ bool MoviePlayer::load(uint32 id) { int lastEnd = -1; _movieTexts.clear(); - while (f.readLine(line, sizeof(line))) { + while (f.readLine_OLD(line, sizeof(line))) { lineNo++; if (line[0] == '#' || line[0] == 0) { continue; @@ -300,9 +300,6 @@ void MoviePlayer::play(void) { terminated = true; } break; - case Common::EVENT_QUIT: - _system->quit(); - break; default: break; } diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp index 980e0b4f9f..d0808d3ece 100644 --- a/engines/sword1/control.cpp +++ b/engines/sword1/control.cpp @@ -215,7 +215,7 @@ void Control::askForCd(void) { notAccepted = false; } } - } while (notAccepted && (!SwordEngine::_systemVars.engineQuit)); + } while (notAccepted && (!g_engine->quit())); _resMan->resClose(fontId); free(_screenBuf); @@ -317,7 +317,7 @@ uint8 Control::runPanel(void) { } delay(1000 / 12); newMode = getClicks(mode, &retVal); - } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!SwordEngine::_systemVars.engineQuit)); + } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!g_engine->quit())); if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) { uint8 volL, volR; @@ -425,7 +425,7 @@ uint8 Control::handleButtonClick(uint8 id, uint8 mode, uint8 *retVal) { _buttons[5]->setSelected(SwordEngine::_systemVars.showText); } else if (id == BUTTON_QUIT) { if (getConfirm(_lStrings[STR_QUIT])) - SwordEngine::_systemVars.engineQuit = true; + g_engine->quitGame(); return mode; } break; @@ -703,7 +703,7 @@ void Control::handleSaveKey(Common::KeyState kbd) { bool Control::saveToFile(void) { if ((_selectedSavegame == 255) || !strlen((char*)_saveNames[_selectedSavegame])) return false; // no saveslot selected or no name entered - saveGameToFile(_selectedSavegame); + saveGameToFile(_numSaves); writeSavegameDescriptions(); return true; } @@ -741,6 +741,7 @@ void Control::readSavegameDescriptions(void) { curFileNum++; } while ((ch != 255) && (!inf->eos())); _saveFiles = curFileNum; + _numSaves = _saveFiles; } delete inf; } @@ -1091,9 +1092,6 @@ void Control::delay(uint32 msecs) { _mouseDown = false; _mouseState |= BS1_WHEEL_DOWN; break; - case Common::EVENT_QUIT: - SwordEngine::_systemVars.engineQuit = true; - break; default: break; } diff --git a/engines/sword1/control.h b/engines/sword1/control.h index 7d9af2f199..926db757b9 100644 --- a/engines/sword1/control.h +++ b/engines/sword1/control.h @@ -98,6 +98,7 @@ private: void deselectSaveslots(void); uint8 *_restoreBuf; uint8 _saveFiles; + uint8 _numSaves; uint8 _saveScrollPos; uint8 _selectedSavegame; uint8 _saveNames[64][32]; diff --git a/engines/sword1/credits.cpp b/engines/sword1/credits.cpp index 14dd0ecd2b..258784ab53 100644 --- a/engines/sword1/credits.cpp +++ b/engines/sword1/credits.cpp @@ -125,7 +125,7 @@ void CreditsPlayer::play(void) { uint16 renderY = BUFSIZE_Y / 2; uint16 clearY = 0xFFFF; bool clearLine = false; - while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) { + while (((*textData != FNT_EOB) || (scrollY != renderY)) && !g_engine->quit()) { if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio if (scrollY < BUFSIZE_Y - CREDITS_Y) _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y); @@ -175,7 +175,7 @@ void CreditsPlayer::play(void) { uint8 *revoBuf = credFile.decompressFile(REVO_LOGO); uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen); _palLen /= 3; - while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) { + while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !g_engine->quit()) { delay(100); } memset(_palette, 0, 256 * 4); @@ -184,13 +184,13 @@ void CreditsPlayer::play(void) { _system->updateScreen(); fadePalette(revoPal, true, _palLen); - while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) { + while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !g_engine->quit()) { delay(100); } fadePalette(revoPal, false, _palLen); delay(3000); - if (SwordEngine::_systemVars.engineQuit) + if (g_engine->quit()) _mixer->stopAll(); free(revoBuf); } @@ -200,7 +200,7 @@ void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) { int fadeStart = fadeup ? 0 : 12; int relDelay = _system->getMillis(); - for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) { + for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !g_engine->quit(); fadeStep += fadeDir) { for (uint16 cnt = 0; cnt < len * 3; cnt++) _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12; _system->setPalette(_palette, 0, 256); @@ -280,13 +280,12 @@ void CreditsPlayer::delay(int msecs) { do { Common::EventManager *eventMan = _system->getEventManager(); while (eventMan->pollEvent(event)) { +#if 0 switch (event.type) { - case Common::EVENT_QUIT: - SwordEngine::_systemVars.engineQuit = true; - break; default: break; } +#endif } _system->updateScreen(); @@ -294,7 +293,7 @@ void CreditsPlayer::delay(int msecs) { if (msecs > 0) _system->delayMillis(10); - } while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit); + } while ((_system->getMillis() < start + msecs) && !g_engine->quit()); } ArcFile::ArcFile(void) { diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index e7e1fb39a4..2fa108ebdd 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -1636,7 +1636,7 @@ int Logic::fnQuitGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, if (SwordEngine::_systemVars.isDemo) { GUI::MessageDialog dialog("This is the end of the Broken Sword 1 Demo", "OK", NULL); dialog.runModal(); - SwordEngine::_systemVars.engineQuit = true; + g_engine->quitGame(); } else error("fnQuitGame() called"); return fnQuit(cpt, id, 0, 0, 0, 0, 0, 0); diff --git a/engines/sword1/music.cpp b/engines/sword1/music.cpp index 6cb82bc0b0..27e7568fcc 100644 --- a/engines/sword1/music.cpp +++ b/engines/sword1/music.cpp @@ -80,7 +80,7 @@ BaseAudioStream::~BaseAudioStream() { void BaseAudioStream::reinit(int size, int rate, byte flags) { _isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0; _rate = rate; - assert((uint)size <= (_sourceStream->size() - _sourceStream->pos())); + assert(size <= (_sourceStream->size() - _sourceStream->pos())); _bitsPerSample = ((flags & Audio::Mixer::FLAG_16BITS) != 0) ? 16 : 8; _samplesLeft = (size * 8) / _bitsPerSample; if ((_bitsPerSample != 16) && (_bitsPerSample != 8)) diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp index 7372779199..9b79f59a32 100644 --- a/engines/sword1/sword1.cpp +++ b/engines/sword1/sword1.cpp @@ -32,6 +32,7 @@ #include "common/fs.h" #include "common/timer.h" #include "common/events.h" +#include "common/savefile.h" #include "common/system.h" #include "engines/metaengine.h" @@ -94,13 +95,22 @@ public: return "Broken Sword Games (C) Revolution"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual GameDescriptor findGame(const char *gameid) const; - virtual GameList detectGames(const FSList &fslist) const; + virtual GameList detectGames(const Common::FSList &fslist) const; + virtual SaveStateList listSaves(const char *target) const; virtual PluginError createInstance(OSystem *syst, Engine **engine) const; }; +bool SwordMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad); +} + GameList SwordMetaEngine::getSupportedGames() const { GameList games; games.push_back(sword1FullSettings); @@ -122,8 +132,8 @@ GameDescriptor SwordMetaEngine::findGame(const char *gameid) const { return GameDescriptor(); } -void Sword1CheckDirectory(const FSList &fslist, bool *filesFound) { - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { +void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound) { + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (!file->isDirectory()) { const char *fileName = file->getName().c_str(); for (int cnt = 0; cnt < NUM_FILES_TO_CHECK; cnt++) @@ -132,15 +142,15 @@ void Sword1CheckDirectory(const FSList &fslist, bool *filesFound) { } else { for (int cnt = 0; cnt < ARRAYSIZE(g_dirNames); cnt++) if (scumm_stricmp(file->getName().c_str(), g_dirNames[cnt]) == 0) { - FSList fslist2; - if (file->getChildren(fslist2, FilesystemNode::kListFilesOnly)) + Common::FSList fslist2; + if (file->getChildren(fslist2, Common::FilesystemNode::kListFilesOnly)) Sword1CheckDirectory(fslist2, filesFound); } } } } -GameList SwordMetaEngine::detectGames(const FSList &fslist) const { +GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const { int i, j; GameList detectedGames; bool filesFound[NUM_FILES_TO_CHECK]; @@ -187,6 +197,47 @@ PluginError SwordMetaEngine::createInstance(OSystem *syst, Engine **engine) cons return kNoError; } +SaveStateList SwordMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + SaveStateList saveList; + + Common::String pattern = "SAVEGAME.???"; + Common::StringList filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); + Common::StringList::const_iterator file = filenames.begin(); + + Common::InSaveFile *in = saveFileMan->openForLoading("SAVEGAME.INF"); + if (in) { + uint8 stop; + char saveDesc[32]; + do { + // Obtain the last digit of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 1); + + uint pos = 0; + do { + stop = in->readByte(); + if (pos < (sizeof(saveDesc) - 1)) { + if ((stop == 10) || (stop == 255) || (in->eos())) { + saveDesc[pos++] = '\0'; + } + else if (stop >= 32) { + saveDesc[pos++] = stop; + } + } + } while ((stop != 10) && (stop != 255) && (!in->eos())); + if (saveDesc[0] != 0) { + saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file)); + file++; + } + } while ((stop != 255) && (!in->eos())); + } + + delete in; + + return saveList; +} + #if PLUGIN_ENABLED_DYNAMIC(SWORD1) REGISTER_PLUGIN_DYNAMIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine); #else @@ -206,14 +257,14 @@ SwordEngine::SwordEngine(OSystem *syst) _features = 0; // Add default file directories - Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/"); - Common::File::addDefaultDirectory(_gameDataPath + "MUSIC/"); - Common::File::addDefaultDirectory(_gameDataPath + "SPEECH/"); - Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/"); - Common::File::addDefaultDirectory(_gameDataPath + "clusters/"); - Common::File::addDefaultDirectory(_gameDataPath + "music/"); - Common::File::addDefaultDirectory(_gameDataPath + "speech/"); - Common::File::addDefaultDirectory(_gameDataPath + "video/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("MUSIC")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("SPEECH")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("music")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("speech")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); } SwordEngine::~SwordEngine() { @@ -247,8 +298,6 @@ int SwordEngine::init() { _resMan = new ResMan("swordres.rif", _systemVars.isMac); debug(5, "Starting object manager"); _objectMan = new ObjectMan(_resMan); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, Audio::Mixer::kMaxMixerVolume); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); _mouse = new Mouse(_system, _resMan, _objectMan); _screen = new Screen(_system, _resMan, _objectMan); _music = new Music(_mixer); @@ -257,60 +306,13 @@ int SwordEngine::init() { _logic = new Logic(_objectMan, _resMan, _screen, _mouse, _sound, _music, _menu, _system, _mixer); _mouse->useLogicAndMenu(_logic, _menu); - uint musicVol = ConfMan.getInt("music_volume"); - uint speechVol = ConfMan.getInt("speech_volume"); - uint sfxVol = ConfMan.getInt("sfx_volume"); - uint musicBal = 50; - if (ConfMan.hasKey("music_balance")) { - musicBal = CLIP(ConfMan.getInt("music_balance"), 0, 100); - } - uint speechBal = 50; - if (ConfMan.hasKey("speech_balance")) { - speechBal = CLIP(ConfMan.getInt("speech_balance"), 0, 100); - } - uint sfxBal = 50; - if (ConfMan.hasKey("sfx_balance")) { - sfxBal = CLIP(ConfMan.getInt("sfx_balance"), 0, 100); - } - - uint musicVolL = 2 * musicVol * musicBal / 100; - uint musicVolR = 2 * musicVol - musicVolL; - - uint speechVolL = 2 * speechVol * speechBal / 100; - uint speechVolR = 2 * speechVol - speechVolL; - - uint sfxVolL = 2 * sfxVol * sfxBal / 100; - uint sfxVolR = 2 * sfxVol - sfxVolL; - - if (musicVolR > 255) { - musicVolR = 255; - } - if (musicVolL > 255) { - musicVolL = 255; - } - if (speechVolR > 255) { - speechVolR = 255; - } - if (speechVolL > 255) { - speechVolL = 255; - } - if (sfxVolR > 255) { - sfxVolR = 255; - } - if (sfxVolL > 255) { - sfxVolL = 255; - } - - _music->setVolume(musicVolL, musicVolR); - _sound->setSpeechVol(speechVolL, speechVolR); - _sound->setSfxVol(sfxVolL, sfxVolR); + syncSoundSettings(); _systemVars.justRestoredGame = 0; _systemVars.currentCD = 0; _systemVars.controlPanelMode = CP_NEWGAME; _systemVars.forceRestart = false; _systemVars.wantFade = true; - _systemVars.engineQuit = false; switch (Common::parseLanguage(ConfMan.get("language"))) { case Common::DE_DEU: @@ -358,6 +360,62 @@ void SwordEngine::reinitialize(void) { _systemVars.wantFade = true; } +void SwordEngine::syncSoundSettings() { + uint musicVol = ConfMan.getInt("music_volume"); + uint sfxVol = ConfMan.getInt("sfx_volume"); + uint speechVol = ConfMan.getInt("speech_volume"); + + uint musicBal = 50; + if (ConfMan.hasKey("music_balance")) { + musicBal = CLIP(ConfMan.getInt("music_balance"), 0, 100); + } + + uint speechBal = 50; + if (ConfMan.hasKey("speech_balance")) { + speechBal = CLIP(ConfMan.getInt("speech_balance"), 0, 100); + } + uint sfxBal = 50; + if (ConfMan.hasKey("sfx_balance")) { + sfxBal = CLIP(ConfMan.getInt("sfx_balance"), 0, 100); + } + + uint musicVolL = 2 * musicVol * musicBal / 100; + uint musicVolR = 2 * musicVol - musicVolL; + + uint speechVolL = 2 * speechVol * speechBal / 100; + uint speechVolR = 2 * speechVol - speechVolL; + + uint sfxVolL = 2 * sfxVol * sfxBal / 100; + uint sfxVolR = 2 * sfxVol - sfxVolL; + + if (musicVolR > 255) { + musicVolR = 255; + } + if (musicVolL > 255) { + musicVolL = 255; + } + + if (speechVolR > 255) { + speechVolR = 255; + } + if (speechVolL > 255) { + speechVolL = 255; + } + if (sfxVolR > 255) { + sfxVolR = 255; + } + if (sfxVolL > 255) { + sfxVolL = 255; + } + + _music->setVolume(musicVolL, musicVolR); + _sound->setSpeechVol(speechVolL, speechVolR); + _sound->setSfxVol(sfxVolL, sfxVolR); + + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); +} + void SwordEngine::flagsToBool(bool *dest, uint8 flags) { uint8 bitPos = 0; while (flags) { @@ -639,13 +697,13 @@ int SwordEngine::go() { int saveSlot = ConfMan.getInt("save_slot"); // Savegames are numbered starting from 1 in the dialog window, // but their filenames are numbered starting from 0. - if (saveSlot > 0 && _control->restoreGameFromFile(saveSlot - 1)) { + if (saveSlot >= 0 && _control->savegamesExist() && _control->restoreGameFromFile(saveSlot)) { _control->doRestore(); } else if (_control->savegamesExist()) { _systemVars.controlPanelMode = CP_NEWGAME; if (_control->runPanel() == CONTROL_GAME_RESTORED) _control->doRestore(); - else if (!_systemVars.engineQuit) + else if (!quit()) _logic->startPositions(0); } else { // no savegames, start new game. @@ -654,10 +712,10 @@ int SwordEngine::go() { } _systemVars.controlPanelMode = CP_NORMAL; - while (!_systemVars.engineQuit) { + while (!quit()) { uint8 action = mainLoop(); - if (!_systemVars.engineQuit) { + if (!quit()) { // the mainloop was left, we have to reinitialize. reinitialize(); if (action == CONTROL_GAME_RESTORED) @@ -698,7 +756,7 @@ uint8 SwordEngine::mainLoop(void) { uint8 retCode = 0; _keyPressed.reset(); - while ((retCode == 0) && (!_systemVars.engineQuit)) { + while ((retCode == 0) && (!quit())) { // do we need the section45-hack from sword.c here? checkCd(); @@ -747,9 +805,9 @@ uint8 SwordEngine::mainLoop(void) { } _mouseState = 0; _keyPressed.reset(); - } while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!_systemVars.engineQuit)); + } while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!quit())); - if ((retCode == 0) && (Logic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade && (!_systemVars.engineQuit)) { + if ((retCode == 0) && (Logic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade && (!quit())) { _screen->fadeDownPalette(); int32 relDelay = (int32)_system->getMillis(); while (_screen->stillFading()) { @@ -796,9 +854,6 @@ void SwordEngine::delay(int32 amount) { //copied and mutilated from sky.cpp _mouseState |= BS1R_BUTTON_UP; _mouseCoord = event.mouse; break; - case Common::EVENT_QUIT: - _systemVars.engineQuit = true; - break; default: break; } diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h index cfb6750a47..5bc80b4f6d 100644 --- a/engines/sword1/sword1.h +++ b/engines/sword1/sword1.h @@ -58,7 +58,6 @@ struct SystemVars { bool runningFromCd; uint32 currentCD; // starts at zero, then either 1 or 2 depending on section being played uint32 justRestoredGame; // see main() in sword.c & New_screen() in gtm_core.c - bool engineQuit; uint8 controlPanelMode; // 1 death screen version of the control panel, 2 = successful end of game, 3 = force restart bool forceRestart; @@ -78,6 +77,7 @@ public: virtual ~SwordEngine(); static SystemVars _systemVars; void reinitialize(void); + virtual void syncSoundSettings(); uint32 _features; protected: diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 48196a2f7d..76f14851e7 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -357,8 +357,8 @@ bool MoviePlayer::userInterrupt() { case Common::EVENT_SCREEN_CHANGED: handleScreenChanged(); break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: - _vm->closeGame(); terminate = true; break; case Common::EVENT_KEYDOWN: @@ -379,7 +379,7 @@ void MoviePlayer::play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn bool startNextText = false; // This happens if the user quits during the "eye" cutscene. - if (_vm->_quit) + if (_vm->quit()) return; _numSpeechLines = numLines; diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp index 6b466d6be0..dcacbc78d4 100644 --- a/engines/sword2/controls.cpp +++ b/engines/sword2/controls.cpp @@ -396,7 +396,7 @@ int Dialog::runModal() { _vm->_system->delayMillis(20); - if (_vm->_quit) + if (_vm->quit()) setResult(0); } @@ -842,7 +842,7 @@ int StartDialog::runModal() { if (startDialog.runModal()) return 1; - if (_vm->_quit) + if (_vm->quit()) return 0; RestoreDialog restoreDialog(_vm); @@ -850,7 +850,7 @@ int StartDialog::runModal() { if (restoreDialog.runModal()) return 0; - if (_vm->_quit) + if (_vm->quit()) return 0; } @@ -882,7 +882,7 @@ int QuitDialog::runModal() { int result = MiniDialog::runModal(); if (result) - _vm->closeGame(); + _vm->quitGame(); return result; } diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp index 84a5b5af76..31b799386f 100644 --- a/engines/sword2/function.cpp +++ b/engines/sword2/function.cpp @@ -2388,7 +2388,7 @@ int32 Logic::fnPlayCredits(int32 *params) { // params: none if (readVar(DEMO)) { - _vm->closeGame(); + _vm->quitGame(); return IR_STOP; } diff --git a/engines/sword2/palette.cpp b/engines/sword2/palette.cpp index 81f93c77ae..b66a3c9a81 100644 --- a/engines/sword2/palette.cpp +++ b/engines/sword2/palette.cpp @@ -212,7 +212,7 @@ uint8 Screen::getFadeStatus() { } void Screen::waitForFade() { - while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->_quit) { + while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->quit()) { updateDisplay(); _vm->_system->delayMillis(20); } diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp index 8cddddff78..326f90cd82 100644 --- a/engines/sword2/resman.cpp +++ b/engines/sword2/resman.cpp @@ -113,7 +113,7 @@ bool ResourceManager::init() { // The resource.inf file is a simple text file containing the names of // all the resource files. - while (file.readLine(_resFiles[_totalClusters].fileName, sizeof(_resFiles[_totalClusters].fileName))) { + while (file.readLine_OLD(_resFiles[_totalClusters].fileName, sizeof(_resFiles[_totalClusters].fileName))) { _resFiles[_totalClusters].numEntries = -1; _resFiles[_totalClusters].entryTab = NULL; if (++_totalClusters >= MAX_res_files) { @@ -412,7 +412,7 @@ Common::File *ResourceManager::openCluFile(uint16 fileNum) { // quit while the game is asking for the user to insert a CD. // But recovering from this situation gracefully is just too // much trouble, so quit now. - if (_vm->_quit) + if (_vm->quit()) g_system->quit(); // If the file is supposed to be on hard disk, or we're diff --git a/engines/sword2/screen.cpp b/engines/sword2/screen.cpp index fdabb3ee6f..1faef01939 100644 --- a/engines/sword2/screen.cpp +++ b/engines/sword2/screen.cpp @@ -389,7 +389,7 @@ void Screen::displayMsg(byte *text, int time) { uint32 targetTime = _vm->getMillis() + (time * 1000); _vm->sleepUntil(targetTime); } else { - while (!_vm->_quit) { + while (!_vm->quit()) { MouseEvent *me = _vm->mouseEvent(); if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN))) break; @@ -919,7 +919,7 @@ void Screen::rollCredits() { while (1) { char buffer[80]; - char *line = f.readLine(buffer, sizeof(buffer)); + char *line = f.readLine_OLD(buffer, sizeof(buffer)); if (!line || *line == 0) { if (!hasCenterMark) { @@ -1035,7 +1035,7 @@ void Screen::rollCredits() { uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); - while (scrollPos < scrollSteps && !_vm->_quit) { + while (scrollPos < scrollSteps && !_vm->quit()) { clearScene(); for (i = startLine; i < lineCount; i++) { @@ -1123,13 +1123,13 @@ void Screen::rollCredits() { // The music should either have stopped or be about to stop, so // wait for it to really happen. - while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) { + while (_vm->_sound->musicTimeRemaining() && !_vm->quit()) { updateDisplay(false); _vm->_system->delayMillis(100); } } - if (_vm->_quit) + if (_vm->quit()) return; waitForFade(); diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h index b89ef8f12b..684be3dacd 100644 --- a/engines/sword2/sound.h +++ b/engines/sword2/sound.h @@ -124,7 +124,7 @@ struct SoundFileHandle { Common::File file; uint32 *idxTab; uint32 idxLen; - uint32 fileSize; + int32 fileSize; uint32 fileType; volatile bool inUse; }; diff --git a/engines/sword2/startup.cpp b/engines/sword2/startup.cpp index 1841384897..09bf65bf75 100644 --- a/engines/sword2/startup.cpp +++ b/engines/sword2/startup.cpp @@ -64,19 +64,23 @@ bool Sword2Engine::initStartMenu() { // extract the filenames int start_ids[MAX_starts]; - char buf[10]; - int lineno = 0; - while (fp.readLine(buf, sizeof(buf))) { + while (!fp.eos() && !fp.ioFailed()) { + Common::String line = fp.readLine(); + + // Skip empty lines or, more likely, the end of the stream. + if (line.size() == 0) + continue; + char *errptr; int id; lineno++; - id = strtol(buf, &errptr, 10); + id = strtol(line.c_str(), &errptr, 10); if (*errptr) { - warning("startup.inf:%d: Invalid string '%s'", lineno, buf); + warning("startup.inf:%d: Invalid string '%s'", lineno, line.c_str()); continue; } @@ -98,6 +102,10 @@ bool Sword2Engine::initStartMenu() { } } + // An I/O error before EOS? That's bad, but this is not a vital file. + if (fp.ioFailed() && !fp.eos()) + warning("I/O error while reading startup.inf"); + fp.close(); // Using this method the Gode generated resource.inf must have #0d0a diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index 7331d1f761..dc884eaacb 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -33,6 +33,7 @@ #include "common/file.h" #include "common/fs.h" #include "common/events.h" +#include "common/savefile.h" #include "common/system.h" #include "engines/metaengine.h" @@ -79,13 +80,24 @@ public: return "Broken Sword Games (C) Revolution"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual GameList getSupportedGames() const; virtual GameDescriptor findGame(const char *gameid) const; - virtual GameList detectGames(const FSList &fslist) const; + virtual GameList detectGames(const Common::FSList &fslist) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; virtual PluginError createInstance(OSystem *syst, Engine **engine) const; }; +bool Sword2MetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + GameList Sword2MetaEngine::getSupportedGames() const { const Sword2::GameSettings *g = Sword2::sword2_settings; GameList games; @@ -106,10 +118,10 @@ GameDescriptor Sword2MetaEngine::findGame(const char *gameid) const { return GameDescriptor(g->gameid, g->description); } -GameList Sword2MetaEngine::detectGames(const FSList &fslist) const { +GameList Sword2MetaEngine::detectGames(const Common::FSList &fslist) const { GameList detectedGames; const Sword2::GameSettings *g; - FSList::const_iterator file; + Common::FSList::const_iterator file; // TODO: It would be nice if we had code here which distinguishes // between the 'sword2' and 'sword2demo' targets. The current code @@ -139,8 +151,8 @@ GameList Sword2MetaEngine::detectGames(const FSList &fslist) const { const char *fileName = file->getName().c_str(); if (0 == scumm_stricmp("clusters", fileName)) { - FSList recList; - if (file->getChildren(recList, FilesystemNode::kListAll)) { + Common::FSList recList; + if (file->getChildren(recList, Common::FilesystemNode::kListAll)) { GameList recGames(detectGames(recList)); if (!recGames.empty()) { detectedGames.push_back(recGames); @@ -156,13 +168,52 @@ GameList Sword2MetaEngine::detectGames(const FSList &fslist) const { return detectedGames; } +SaveStateList Sword2MetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + char saveDesc[SAVE_DESCRIPTION_LEN]; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + in->readUint32LE(); + in->read(saveDesc, SAVE_DESCRIPTION_LEN); + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + delete in; + } + } + } + + return saveList; +} + +void Sword2MetaEngine::removeSaveState(const char *target, int slot) const { + char extension[6]; + snprintf(extension, sizeof(extension), ".%03d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + PluginError Sword2MetaEngine::createInstance(OSystem *syst, Engine **engine) const { assert(syst); assert(engine); - FSList fslist; - FilesystemNode dir(ConfMan.get("path")); - if (!dir.getChildren(fslist, FilesystemNode::kListAll)) { + Common::FSList fslist; + Common::FilesystemNode dir(ConfMan.get("path")); + if (!dir.getChildren(fslist, Common::FilesystemNode::kListAll)) { return kInvalidPathError; } @@ -190,12 +241,12 @@ namespace Sword2 { Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) { // Add default file directories - Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/"); - Common::File::addDefaultDirectory(_gameDataPath + "SWORD2/"); - Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/"); - Common::File::addDefaultDirectory(_gameDataPath + "clusters/"); - Common::File::addDefaultDirectory(_gameDataPath + "sword2/"); - Common::File::addDefaultDirectory(_gameDataPath + "video/"); + Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("SWORD2")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("sword2")); + Common::File::addDefaultDirectory(_gameDataDir.getChild("video")); if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo")) _features = GF_DEMO; @@ -229,7 +280,6 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) { _gameCycle = 0; _gameSpeed = 1; - _quit = false; syst->getEventManager()->registerRandomSource(_rnd, "sword2"); } @@ -371,7 +421,7 @@ int Sword2Engine::init() { // player will kill the music for us. Otherwise, the restore // will either have killed the music, or done a crossfade. - if (_quit) + if (quit()) return 0; if (result) @@ -443,7 +493,7 @@ int Sword2Engine::go() { // because we want the break to happen before updating the // screen again. - if (_quit) + if (quit()) break; // creates the debug text blocks @@ -463,10 +513,6 @@ int Sword2Engine::go() { return 0; } -void Sword2Engine::closeGame() { - _quit = true; -} - void Sword2Engine::restartGame() { ScreenInfo *screenInfo = _screen->getScreenInfo(); uint32 temp_demo_flag; @@ -610,9 +656,6 @@ void Sword2Engine::parseInputEvents() { _mouseEvent.buttons = RD_WHEELDOWN; } break; - case Common::EVENT_QUIT: - closeGame(); - break; default: break; } diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h index 05c5d7fa47..9b589c347e 100644 --- a/engines/sword2/sword2.h +++ b/engines/sword2/sword2.h @@ -141,8 +141,6 @@ public: bool getSubtitles() { return _useSubtitles; } void setSubtitles(bool b) { _useSubtitles = b; } - bool _quit; - uint32 _features; MemoryManager *_memory; @@ -210,7 +208,6 @@ public: void startGame(); void gameCycle(); - void closeGame(); void restartGame(); void sleepUntil(uint32 time); diff --git a/engines/tinsel/config.cpp b/engines/tinsel/config.cpp index 4c143f1b8d..803d2231e4 100644 --- a/engines/tinsel/config.cpp +++ b/engines/tinsel/config.cpp @@ -24,8 +24,6 @@ * This file contains configuration functionality */ -//#define USE_3FLAGS 1 - #include "tinsel/config.h" #include "tinsel/dw.h" #include "tinsel/sound.h" @@ -41,13 +39,13 @@ namespace Tinsel { //----------------- GLOBAL GLOBAL DATA -------------------- int dclickSpeed = DOUBLE_CLICK_TIME; -int volMidi = MAXMIDIVOL; -int volSound = MAXSAMPVOL; -int volVoice = MAXSAMPVOL; +int volMidi = Audio::Mixer::kMaxChannelVolume; +int volSound = Audio::Mixer::kMaxChannelVolume; +int volVoice = Audio::Mixer::kMaxChannelVolume; int speedText = DEFTEXTSPEED; int bSubtitles = false; int bSwapButtons = 0; -LANGUAGE language = TXT_ENGLISH; +LANGUAGE g_language = TXT_ENGLISH; int bAmerica = 0; @@ -55,19 +53,43 @@ int bAmerica = 0; bool bNoBlocking; /** - * WriteConfig() + * Write settings to config manager and flush the config file to disk. */ - void WriteConfig(void) { ConfMan.setInt("dclick_speed", dclickSpeed); - ConfMan.setInt("music_volume", (volMidi * Audio::Mixer::kMaxChannelVolume) / MAXMIDIVOL); - ConfMan.setInt("sfx_volume", (volSound * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL); - ConfMan.setInt("speech_volume", (volVoice * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL); + ConfMan.setInt("music_volume", volMidi); + ConfMan.setInt("sfx_volume", volSound); + ConfMan.setInt("speech_volume", volVoice); ConfMan.setInt("talkspeed", (speedText * 255) / 100); ConfMan.setBool("subtitles", bSubtitles); //ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0); - //ConfigData.language = language; // not necessary, as language has been set in the launcher //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB + + // Store language for multilingual versions + if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) { + Common::Language lang; + switch (g_language) { + case TXT_FRENCH: + lang = Common::FR_FRA; + break; + case TXT_GERMAN: + lang = Common::DE_DEU; + break; + case TXT_SPANISH: + lang = Common::ES_ESP; + break; + case TXT_ITALIAN: + lang = Common::IT_ITA; + break; + default: + lang = Common::EN_ANY; + } + + ConfMan.set("language", Common::getLanguageCode(lang)); + } + + // Write to disk + ConfMan.flushToDisk(); } /*---------------------------------------------------------------------*\ @@ -79,9 +101,9 @@ void ReadConfig(void) { if (ConfMan.hasKey("dclick_speed")) dclickSpeed = ConfMan.getInt("dclick_speed"); - volMidi = (ConfMan.getInt("music_volume") * MAXMIDIVOL) / Audio::Mixer::kMaxChannelVolume; - volSound = (ConfMan.getInt("sfx_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume; - volVoice = (ConfMan.getInt("speech_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume; + volMidi = ConfMan.getInt("music_volume"); + volSound = ConfMan.getInt("sfx_volume"); + volVoice = ConfMan.getInt("speech_volume"); if (ConfMan.hasKey("talkspeed")) speedText = (ConfMan.getInt("talkspeed") * 100) / 255; @@ -94,24 +116,53 @@ void ReadConfig(void) { //ConfigData.language = language; // not necessary, as language has been set in the launcher //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB -// The flags here control how many country flags are displayed in one of the option dialogs. -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) - language = ConfigData.language; - #ifdef USE_3FLAGS - if (language == TXT_ENGLISH || language == TXT_ITALIAN) { - language = TXT_GERMAN; - bSubtitles = true; + // Set language - we'll be clever here and use the ScummVM language setting + g_language = TXT_ENGLISH; + Common::Language lang = _vm->getLanguage(); + if (lang == Common::UNK_LANG && ConfMan.hasKey("language")) + lang = Common::parseLanguage(ConfMan.get("language")); // For multi-lingual versions, fall back to user settings + switch (lang) { + case Common::FR_FRA: + g_language = TXT_FRENCH; + break; + case Common::DE_DEU: + g_language = TXT_GERMAN; + break; + case Common::ES_ESP: + g_language = TXT_SPANISH; + break; + case Common::IT_ITA: + g_language = TXT_ITALIAN; + break; + default: + g_language = TXT_ENGLISH; } - #endif - #ifdef USE_4FLAGS - if (language == TXT_ENGLISH) { - language = TXT_GERMAN; + + if (lang == Common::JA_JPN) { + // TODO: Add support for JAPAN version + } else if (lang == Common::HB_ISR) { + // TODO: Add support for HEBREW version + + // The Hebrew version appears to the software as being English + // but it needs to have subtitles on... + g_language = TXT_ENGLISH; bSubtitles = true; + } else if (_vm->getFeatures() & GF_USE_3FLAGS) { + // 3 FLAGS version supports French, German, Spanish + // Fall back to German if necessary + if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && g_language != TXT_SPANISH) { + g_language = TXT_GERMAN; + bSubtitles = true; + } + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + // 4 FLAGS version supports French, German, Spanish, Italian + // Fall back to German if necessary + if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && + g_language != TXT_SPANISH && g_language != TXT_ITALIAN) { + g_language = TXT_GERMAN; + bSubtitles = true; + } } - #endif -#else - language = TXT_ENGLISH; -#endif } bool isJapanMode() { diff --git a/engines/tinsel/config.h b/engines/tinsel/config.h index 73cc411cb6..fc85f0abe0 100644 --- a/engines/tinsel/config.h +++ b/engines/tinsel/config.h @@ -30,23 +30,11 @@ namespace Tinsel { -// None of these defined -> 1 language, in ENGLISH.TXT -//#define USE_5FLAGS 1 // All 5 flags -//#define USE_4FLAGS 1 // French, German, Italian, Spanish -//#define USE_3FLAGS 1 // French, German, Spanish - -// The Hebrew version appears to the software as being English -// but it needs to have subtitles on... -//#define HEBREW 1 - -//#define JAPAN 1 - - // double click timer initial value -#define DOUBLE_CLICK_TIME 6 // 6 @ 18Hz = .33 sec - -#define DEFTEXTSPEED 0 - +enum { + DOUBLE_CLICK_TIME = 6, // 6 @ 18Hz = .33 sec + DEFTEXTSPEED = 0 +}; extern int dclickSpeed; extern int volMidi; @@ -55,7 +43,7 @@ extern int volVoice; extern int speedText; extern int bSubtitles; extern int bSwapButtons; -extern LANGUAGE language; +extern LANGUAGE g_language; extern int bAmerica; void WriteConfig(void); diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp index b95662cbfe..f933b2dd79 100644 --- a/engines/tinsel/cursor.cpp +++ b/engines/tinsel/cursor.cpp @@ -49,7 +49,7 @@ namespace Tinsel { //----------------- LOCAL DEFINES -------------------- #define ITERATION_BASE FRAC_ONE -#define ITER_ACCELLERATION (10L << (FRAC_BITS - 4)) +#define ITER_ACCELERATION (10L << (FRAC_BITS - 4)) //----------------- LOCAL GLOBAL DATA -------------------- @@ -404,7 +404,8 @@ static void MoveCursor(void) { newY = intToFrac(ptMouse.y); // modify mouse driver position depending on cursor keys - if ((dir = _vm->getKeyDirection()) != 0) { + dir = _vm->getKeyDirection(); + if (dir != 0) { if (dir & MSK_LEFT) newX -= IterationSize; @@ -417,7 +418,7 @@ static void MoveCursor(void) { if (dir & MSK_DOWN) newY += IterationSize; - IterationSize += ITER_ACCELLERATION; + IterationSize += ITER_ACCELERATION; // set new mouse driver position _vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY))); diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 7da4192456..526d72e4a4 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -29,6 +29,7 @@ #include "common/file.h" #include "tinsel/tinsel.h" +#include "tinsel/savescn.h" // needed by TinselMetaEngine::listSaves namespace Tinsel { @@ -111,6 +112,30 @@ static const TinselGameDescription gameDescriptions[] = { TINSEL_V1, }, + { // Multilingual floppy with *.gra files. + // Note: It contains no english subtitles. + // Reported on our forums. + { + "dw", + "Floppy", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_FLOPPY | GF_USE_4FLAGS, + TINSEL_V1, + }, + { // English CD. This version has *.gra files { "dw", @@ -130,6 +155,96 @@ static const TinselGameDescription gameDescriptions[] = { TINSEL_V1, }, + { // Multilingual CD with english speech and *.gra files. + // Note: It contains no english subtitles. + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.smp", 0, NULL, -1}, + {"french.txt", 0, NULL, -1}, + {"german.txt", 0, NULL, -1}, + {"italian.txt", 0, NULL, -1}, + {"spanish.txt", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::ES_ESP, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS, + TINSEL_V1, + }, + { // English CD with SCN files { "dw", @@ -189,25 +304,6 @@ static const TinselGameDescription gameDescriptions[] = { { AD_TABLE_END_MARKER, 0, 0, 0, 0 } }; -/** - * The fallback game descriptor used by the Tinsel engine's fallbackDetector. - * Contents of this struct are to be overwritten by the fallbackDetector. - */ -static TinselGameDescription g_fallbackDesc = { - { - "", - "", - AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor - Common::UNK_LANG, - Common::kPlatformPC, - Common::ADGF_NO_FLAGS - }, - 0, - 0, - 0, - 0, -}; - } // End of namespace Tinsel static const Common::ADParams detectionParams = { @@ -238,15 +334,42 @@ public: } virtual const char *getCopyright() const { + // FIXME: Bad copyright string. + // Should be something like "Tinsel (C) Psygnosis" or so... ??? return "Tinsel Engine"; } virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; - const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const; - + virtual bool hasFeature(MetaEngineFeature f) const; + virtual SaveStateList listSaves(const char *target) const; }; +bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves); +} + +namespace Tinsel { +extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &target); +} + +SaveStateList TinselMetaEngine::listSaves(const char *target) const { + int numStates = Tinsel::getList(g_system->getSavefileManager(), target); + + SaveStateList saveList; + for (int i = 0; i < numStates; i++) { + SaveStateDescriptor sd(i, + Tinsel::ListEntry(i, Tinsel::LE_DESC), + Tinsel::ListEntry(i, Tinsel::LE_NAME)); + // TODO: Also add savedFiles[i].dateTime to the SaveStateDescriptor + saveList.push_back(sd); + } + + return saveList; +} + + bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc; if (gd) { @@ -255,21 +378,6 @@ bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm return gd != 0; } -const Common::ADGameDescription *TinselMetaEngine::fallbackDetect(const FSList *fslist) const { - // Set the default values for the fallback descriptor's ADGameDescription part. - Tinsel::g_fallbackDesc.desc.language = Common::UNK_LANG; - Tinsel::g_fallbackDesc.desc.platform = Common::kPlatformPC; - Tinsel::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS; - - // Set default values for the fallback descriptor's TinselGameDescription part. - Tinsel::g_fallbackDesc.gameID = 0; - Tinsel::g_fallbackDesc.features = 0; - Tinsel::g_fallbackDesc.version = 0; - - //return (const Common::ADGameDescription *)&Tinsel::g_fallbackDesc; - return NULL; -} - #if PLUGIN_ENABLED_DYNAMIC(TINSEL) REGISTER_PLUGIN_DYNAMIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine); #else diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h index d14dd43fa2..9ceef37858 100644 --- a/engines/tinsel/dw.h +++ b/engines/tinsel/dw.h @@ -110,8 +110,11 @@ typedef int HPOLYGON; // Language for the resource strings enum LANGUAGE { - TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN, - TXT_ITALIAN, TXT_SPANISH + TXT_ENGLISH, + TXT_FRENCH, + TXT_GERMAN, + TXT_ITALIAN, + TXT_SPANISH }; } // end of namespace Tinsel diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp index 2a0f3695c0..d20ada51ac 100644 --- a/engines/tinsel/inventory.cpp +++ b/engines/tinsel/inventory.cpp @@ -29,8 +29,6 @@ * And there's still a bit of tidying and commenting to do yet. */ -//#define USE_3FLAGS 1 - #include "tinsel/actors.h" #include "tinsel/anim.h" #include "tinsel/background.h" @@ -370,9 +368,7 @@ enum BFUNC { NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN, OPENLOAD, OPENSAVE, OPENREST, OPENSOUND, OPENCONT, -#ifndef JAPAN OPENSUBT, -#endif OPENQUIT, INITGAME, MIDIVOL, CLANG, RLANG @@ -402,9 +398,7 @@ struct CONFBOX { #define SIX_RESTART_OPTION 2 #define SIX_SOUND_OPTION 3 #define SIX_CONTROL_OPTION 4 -#ifndef JAPAN #define SIX_SUBTITLES_OPTION 5 -#endif #define SIX_QUIT_OPTION 6 #define SIX_RESUME_OPTION 7 #define SIX_LOAD_HEADING 8 @@ -531,9 +525,9 @@ CONFBOX restartBox[] = { }; #else CONFBOX soundBox[] = { - { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 25, MAXMIDIVOL, 2, &volMidi, 0 }, - { SLIDER, NOFUNC, NULL, SIX_SVOL_SLIDER, 142, 25+40, MAXSAMPVOL, 2, &volSound, 0 }, - { SLIDER, NOFUNC, NULL, SIX_VVOL_SLIDER, 142, 25+2*40, MAXSAMPVOL, 2, &volVoice, 0 } + { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 25, Audio::Mixer::kMaxChannelVolume, 2, &volMidi, 0 }, + { SLIDER, NOFUNC, NULL, SIX_SVOL_SLIDER, 142, 25+40, Audio::Mixer::kMaxChannelVolume, 2, &volSound, 0 }, + { SLIDER, NOFUNC, NULL, SIX_VVOL_SLIDER, 142, 25+2*40, Audio::Mixer::kMaxChannelVolume, 2, &volVoice, 0 } }; #endif @@ -568,41 +562,60 @@ CONFBOX controlBox[] = { /*-------------------------------------------------------------*\ -| This is the subtitles 'menu'. | +| This is the subtitles 'menu'. | \*-------------------------------------------------------------*/ -#ifndef JAPAN CONFBOX subtitlesBox[] = { -#ifdef USE_5FLAGS + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + +}; + +CONFBOX subtitlesBox3Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox4Flags[] = { + + { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT }, + { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP }, + + { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, + { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, + + { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, + { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } + +}; + +CONFBOX subtitlesBox5Flags[] = { + { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 100, 56, 32, NULL, FIX_UK }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 100, 56, 32, NULL, FIX_FR }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 100, 56, 32, NULL, FIX_GR }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 50, 137, 56, 32, NULL, FIX_IT }, { FRGROUP, NOFUNC, NULL, USE_POINTER, 120, 137, 56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_4FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP }, -#endif -#ifdef USE_3FLAGS - { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR }, - { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP }, -#endif { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 }, { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 }, -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 }, { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 } -#endif }; -#endif /*-------------------------------------------------------------*\ @@ -610,7 +623,7 @@ CONFBOX subtitlesBox[] = { \*-------------------------------------------------------------*/ CONFBOX quitBox[] = { -#ifdef JAPAN +#ifdef g { AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 44, 23, 19, NULL, IX_TICK1 }, { AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 44, 23, 19, NULL, IX_CROSS1 } #else @@ -652,13 +665,9 @@ CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, ARRAYSIZE(soundBox), NO_HEA #else CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, ARRAYSIZE(controlBox), NO_HEADING }; #endif -#ifndef JAPAN -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) -CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; -#else + CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING }; -#endif -#endif + CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, ARRAYSIZE(quitBox), SIX_QUIT_HEADING }; CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING }; @@ -762,45 +771,39 @@ static void ConfActionSpecial(int i); -#ifndef JAPAN bool LanguageChange(void) { - LANGUAGE nLang; - -#ifdef USE_3FLAGS - // VERY quick dodgy bodge - if (cd.selBox == 0) - nLang = TXT_FRENCH; - else if (cd.selBox == 1) - nLang = TXT_GERMAN; - else - nLang = TXT_SPANISH; - if (nLang != language) { -#elif defined(USE_4FLAGS) - nLang = (LANGUAGE)(cd.selBox + 1); - if (nLang != language) { -#else - if (cd.selBox != language) { + LANGUAGE nLang = TXT_ENGLISH; + + if (_vm->getFeatures() & GF_USE_3FLAGS) { + // VERY quick dodgy bodge + if (cd.selBox == 0) + nLang = TXT_FRENCH; // = 1 + else if (cd.selBox == 1) + nLang = TXT_GERMAN; // = 2 + else + nLang = TXT_SPANISH; // = 4 + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + nLang = (LANGUAGE)(cd.selBox + 1); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { nLang = (LANGUAGE)cd.selBox; -#endif + } + + if (nLang != g_language) { KillInventory(); ChangeLanguage(nLang); - language = nLang; + g_language = nLang; return true; - } - else + } else return false; } -#endif /**************************************************************************/ /******************** Some miscellaneous functions ************************/ /**************************************************************************/ -/*---------------------------------------------------------------------*\ -| DumpIconArray()/DumpDobjArray()/DumpObjArray() | -|-----------------------------------------------------------------------| -| Delete all the objects in iconArray[]/DobjArray[]/objArray[] | -\*---------------------------------------------------------------------*/ +/** + * Delete all the objects in iconArray[] + */ static void DumpIconArray(void){ for (int i = 0; i < MAX_ICONS; i++) { if (iconArray[i] != NULL) { @@ -813,7 +816,6 @@ static void DumpIconArray(void){ /** * Delete all the objects in DobjArray[] */ - static void DumpDobjArray(void) { for (int i = 0; i < MAX_WCOMP; i++) { if (DobjArray[i] != NULL) { @@ -826,7 +828,6 @@ static void DumpDobjArray(void) { /** * Delete all the objects in objArray[] */ - static void DumpObjArray(void) { for (int i = 0; i < MAX_WCOMP; i++) { if (objArray[i] != NULL) { @@ -886,7 +887,6 @@ bool IsInInventory(int object, int invnum) { /** * Returns which item is held (INV_NOICON (-1) if none) */ - int WhichItemHeld(void) { return HeldItem; } @@ -895,7 +895,6 @@ int WhichItemHeld(void) { * Called from the cursor module when it re-initialises (at the start of * a new scene). For if we are holding something at scene-change time. */ - void InventoryIconCursor(void) { INV_OBJECT *invObj; @@ -908,7 +907,6 @@ void InventoryIconCursor(void) { /** * Returns TRUE if the inventory is active. */ - bool InventoryActive(void) { return (InventoryState == ACTIVE_INV); } @@ -1214,8 +1212,8 @@ void Select(int i, bool force) { break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w+6, cd.Box[i].h+6); MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]); MultiSetAniXY(iconArray[HL2], @@ -1224,7 +1222,7 @@ void Select(int i, bool force) { MultiSetZPosition(iconArray[HL2], Z_INV_BRECT+1); break; -#endif + default: break; } @@ -1276,7 +1274,6 @@ void DropItem(int item) { * Stick the item into an inventory list (ItemOrder[]), and hold the * item if requested. */ - void AddToInventory(int invno, int icon, bool hold) { int i; bool bOpen; @@ -1407,12 +1404,12 @@ int InvArea(int x, int y) { int RightX = MultiRightmost(RectObject) + 1; int BottomY = MultiLowest(RectObject) + 1; -// Outside the whole rectangle? + // Outside the whole rectangle? if (x <= LeftX - EXTRA || x > RightX + EXTRA || y <= TopY - EXTRA || y > BottomY + EXTRA) return I_NOTIN; -// The bottom line + // The bottom line if (y > BottomY - 2 - EXTRA) { // Below top of bottom line? if (x <= LeftX + 2 + EXTRA) return I_BLEFT; // Bottom left corner @@ -1422,7 +1419,7 @@ int InvArea(int x, int y) { return I_BOTTOM; // Just plain bottom } -// The top line + // The top line if (y <= TopY + 2 + EXTRA) { // Above bottom of top line? if (x <= LeftX + 2 + EXTRA) return I_TLEFT; // Top left corner @@ -1432,24 +1429,24 @@ int InvArea(int x, int y) { return I_TOP; // Just plain top } -// Sides + // Sides if (x <= LeftX + 2 + EXTRA) // Left of right of left side? return I_LEFT; else if (x > RightX - 2 - EXTRA) // Right of left of right side? return I_RIGHT; -// From here down still needs fixing up properly -/* -* In the move area? -*/ + // From here down still needs fixing up properly + /* + * In the move area? + */ if (ino != INV_CONF && x >= LeftX + M_SW - 2 && x <= RightX - M_SW + 3 && y >= TopY + M_TH - 2 && y < TopY + M_TBB + 2) return I_MOVE; -/* -* Scroll bits -*/ + /* + * Scroll bits + */ if (ino == INV_CONF && cd.bExtraWin) { } else { if (x > RightX - M_IAL + 3 && x <= RightX - M_IAR + 1) { @@ -1476,7 +1473,6 @@ int InvArea(int x, int y) { * Returns the id of the icon displayed under the given position. * Also return co-ordinates of items tag display position, if requested. */ - int InvItem(int *x, int *y, bool update) { int itop, ileft; int row, col; @@ -1510,7 +1506,6 @@ int InvItem(int *x, int *y, bool update) { /** * Returns the id of the icon displayed under the given position. */ - int InvItemId(int x, int y) { int itop, ileft; int row, col; @@ -1539,21 +1534,21 @@ int InvItemId(int x, int y) { return INV_NOICON; } -/*---------------------------------------------------------------------*\ -| WhichInvBox() | -|-----------------------------------------------------------------------| -| Finds which box the cursor is in. | -\*---------------------------------------------------------------------*/ -#define MD_YSLIDTOP 7 -#define MD_YSLIDBOT 18 -#define MD_YBUTTOP 9 -#define MD_YBUTBOT 16 -#define MD_XLBUTL 1 -#define MD_XLBUTR 10 -#define MD_XRBUTL 105 -#define MD_XRBUTR 114 - +/** + * Finds which box the cursor is in. + */ static int WhichInvBox(int curX, int curY, bool bSlides) { + enum { + MD_YSLIDTOP = 7, + MD_YSLIDBOT = 18, + MD_YBUTTOP = 9, + MD_YBUTBOT = 16, + MD_XLBUTL = 1, + MD_XLBUTR = 10, + MD_XRBUTL = 105, + MD_XRBUTR = 114 + }; + if (bSlides) { for (int i = 0; i < numMdSlides; i++) { if (curY > MultiHighest(mdSlides[i].obj) && curY < MultiLowest(mdSlides[i].obj) @@ -1841,7 +1836,6 @@ void InvLabels(bool InBody, int aniX, int aniY) { * It seems to set up slideStuff[], an array of possible first-displayed * icons set against the matching y-positions of the slider. */ - void AdjustTop(void) { int tMissing, bMissing, nMissing; int nslideY; @@ -1904,7 +1898,6 @@ void AdjustTop(void) { /** * Insert an inventory icon object onto the display list. */ - OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { INV_OBJECT *invObj; // Icon data const MULTI_INIT *pmi; // Its INIT structure - from the reel @@ -1929,7 +1922,6 @@ OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) { /** * Create display objects for the displayed icons in an inventory window. */ - void FillInInventory(void) { int Index; // Index into ItemOrder[] int n = 0; // index into iconArray[] @@ -2010,7 +2002,6 @@ void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int te /** * Insert a part of the inventory window frame onto the display list. */ - static OBJECT *AddObject(const FREEL *pfreel, int num) { const MULTI_INIT *pmi; // Get the MULTI_INIT structure IMAGE *pim; @@ -2043,7 +2034,6 @@ static OBJECT *AddObject(const FREEL *pfreel, int num) { /** * Display the scroll bar slider. */ - void AddSlider(OBJECT **slide, const FILM *pfilm) { SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); MultiSetAniXY(*slide, MultiRightmost(RectObject)-M_SXOFF+2, InvD[ino].inventoryY + slideY); @@ -2062,7 +2052,6 @@ enum { /** * Display a box with some text in it. */ - void AddBox(int *pi, int i) { int x = InvD[ino].inventoryX + cd.Box[i].xpos; int y = InvD[ino].inventoryY + cd.Box[i].ypos; @@ -2126,8 +2115,8 @@ void AddBox(int *pi, int i) { break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); assert(flagFilm != 0); // Language flags not declared! pfilm = (const FILM *)LockMem(flagFilm); @@ -2141,7 +2130,7 @@ void AddBox(int *pi, int i) { *pi += 1; break; -#endif + case FLIP: pfilm = (const FILM *)LockMem(winPartsf); @@ -2234,7 +2223,6 @@ static void AddBoxes(bool posnSlide) { /** * Display the scroll bar slider. */ - void AddEWSlider(OBJECT **slide, const FILM *pfilm) { SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1); MultiSetAniXY(*slide, InvD[ino].inventoryX + 24 + 127, slideY); @@ -2244,7 +2232,6 @@ void AddEWSlider(OBJECT **slide, const FILM *pfilm) { /** * AddExtraWindow */ - int AddExtraWindow(int x, int y, OBJECT **retObj) { int n = 0; const FILM *pfilm; @@ -2479,7 +2466,7 @@ void ConstructInventory(InventoryType filling) { OBJECT **rect, **title; -// Draw background, slider and icons + // Draw background, slider and icons if (filling == FULL) { rect = &retObj[n++]; title = &retObj[n++]; @@ -2495,8 +2482,7 @@ void ConstructInventory(InventoryType filling) { } FillInInventory(); - } - else if (filling == CONF) { + } else if (filling == CONF) { rect = &retObj[n++]; title = &retObj[n++]; @@ -2800,7 +2786,6 @@ bool convHid(void) { /** * Start up an inventory window. */ - void PopUpInventory(int invno) { assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF)); // Trying to open illegal inventory @@ -2849,7 +2834,6 @@ void SetConfGlobals(CONFINIT *ci) { /** * PopupConf */ - void PopUpConf(CONFTYPE type) { int curX, curY; @@ -2903,11 +2887,27 @@ void PopUpConf(CONFTYPE type) { SetConfGlobals(&ciSound); break; -#ifndef JAPAN case SUBT: + if (_vm->getFeatures() & GF_USE_3FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox3Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox3Flags); + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox4Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { + ciSubtitles.v = 6; + ciSubtitles.Box = subtitlesBox4Flags; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags); + } else { + ciSubtitles.v = 3; + ciSubtitles.Box = subtitlesBox; + ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox); + } + SetConfGlobals(&ciSubtitles); break; -#endif case TOPWIN: SetConfGlobals(&ciTopWin); @@ -2927,25 +2927,21 @@ void PopUpConf(CONFTYPE type) { if (type == SAVE || type == LOAD) Select(0, false); -#ifndef JAPAN -#if !defined(USE_3FLAGS) || !defined(USE_4FLAGS) || !defined(USE_5FLAGS) else if (type == SUBT) { -#ifdef USE_3FLAGS - // VERY quick dirty bodges - if (language == TXT_FRENCH) - Select(0, false); - else if (language == TXT_GERMAN) - Select(1, false); - else - Select(2, false); -#elif defined(USE_4FLAGS) - Select(language-1, false); -#else - Select(language, false); -#endif + if (_vm->getFeatures() & GF_USE_3FLAGS) { + // VERY quick dirty bodges + if (g_language == TXT_FRENCH) + Select(0, false); + else if (g_language == TXT_GERMAN) + Select(1, false); + else + Select(2, false); + } else if (_vm->getFeatures() & GF_USE_4FLAGS) { + Select(g_language-1, false); + } else if (_vm->getFeatures() & GF_USE_5FLAGS) { + Select(g_language, false); + } } -#endif -#endif // JAPAN GetCursorXY(&curX, &curY, false); InvCursor(IC_AREA, curX, curY); @@ -2954,7 +2950,6 @@ void PopUpConf(CONFTYPE type) { /** * Close down an inventory window. */ - void KillInventory(void) { if (objArray[0] != NULL) { DumpObjArray(); @@ -2976,6 +2971,9 @@ void KillInventory(void) { if (bOpenConf) { bOpenConf = false; PopUpConf(OPTION); + + // Write config changes + WriteConfig(); } else if (ino == INV_CONF) InventoryIconCursor(); } @@ -3073,7 +3071,7 @@ void InventoryProcess(CORO_PARAM, const void *) { InvLoadGame(); break; case IQUITGAME: - _vm->quitFlag = true; + _vm->quitGame(); break; case CLOSEWIN: KillInventory(); @@ -3098,12 +3096,10 @@ void InventoryProcess(CORO_PARAM, const void *) { KillInventory(); PopUpConf(CONTROLS); break; - #ifndef JAPAN case OPENSUBT: KillInventory(); PopUpConf(SUBT); break; - #endif case OPENQUIT: KillInventory(); PopUpConf(QUIT); @@ -3112,7 +3108,6 @@ void InventoryProcess(CORO_PARAM, const void *) { KillInventory(); bRestart = true; break; - #if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case CLANG: if (!LanguageChange()) KillInventory(); @@ -3120,7 +3115,6 @@ void InventoryProcess(CORO_PARAM, const void *) { case RLANG: KillInventory(); break; - #endif default: break; } @@ -3344,10 +3338,8 @@ static void SlideMSlider(int x, SSFN fn) { case S_END: // End of a drag on the slider AddBoxes(false); // Might change position slightly -#ifndef JAPAN if (ino == INV_CONF && cd.Box == subtitlesBox) - Select(language, false); -#endif + Select(g_language, false); break; } } @@ -3780,8 +3772,8 @@ void ConfAction(int i, bool dbl) { } break; -#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS) case FRGROUP: + assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)); if (dbl) { Select(i, false); LanguageChange(); @@ -3789,7 +3781,6 @@ void ConfAction(int i, bool dbl) { Select(i, false); } break; -#endif case AAGBUT: case ARSGBUT: diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index 7d4efd8079..d165ba0a10 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -263,7 +263,7 @@ int GetMidiVolume() { * @param vol New volume - 0..MAXMIDIVOL */ void SetMidiVolume(int vol) { - assert(vol >= 0 && vol <= MAXMIDIVOL); + assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume); if (vol == 0 && volMidi == 0) { // Nothing to do @@ -343,10 +343,6 @@ MusicPlayer::~MusicPlayer() { } void MusicPlayer::setVolume(int volume) { - Common::StackLock lock(_mutex); - - // FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range? - volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255); _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); if (_masterVolume == volume) @@ -354,6 +350,8 @@ void MusicPlayer::setVolume(int volume) { _masterVolume = volume; + Common::StackLock lock(_mutex); + for (int i = 0; i < 16; ++i) { if (_channel[i]) { _channel[i]->volume(_channelVolume[i] * _masterVolume / 255); diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h index 80456e2a76..3d647f95bf 100644 --- a/engines/tinsel/music.h +++ b/engines/tinsel/music.h @@ -34,8 +34,6 @@ namespace Tinsel { -#define MAXMIDIVOL 127 - bool PlayMidiSequence( // Plays the specified MIDI sequence through the sound driver uint32 dwFileOffset, // handle of MIDI sequence data bool bLoop); // Whether to loop the sequence diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index 1a6cc1202a..acdaf6c0bb 100644 --- a/engines/tinsel/saveload.cpp +++ b/engines/tinsel/saveload.cpp @@ -246,16 +246,11 @@ static char *NewName(void) { * Store the file details, ordered by time, in savedFiles[] and return * the number of files found). */ -int getList(void) { - // No change since last call? - // TODO/FIXME: Just always reload this data? Be careful about slow downs!!! - if (!NeedLoad) - return numSfiles; - +int getList(Common::SaveFileManager *saveFileMan, const Common::String &target) { int i; - const Common::String pattern = _vm->getSavegamePattern(); - Common::StringList files = _vm->getSaveFileMan()->listSavefiles(pattern.c_str()); + const Common::String pattern = target + ".???"; + Common::StringList files = saveFileMan->listSavefiles(pattern.c_str()); numSfiles = 0; @@ -264,7 +259,7 @@ int getList(void) { break; const Common::String &fname = *file; - Common::InSaveFile *f = _vm->getSaveFileMan()->openForLoading(fname.c_str()); + Common::InSaveFile *f = saveFileMan->openForLoading(fname.c_str()); if (f == NULL) { continue; } @@ -304,6 +299,15 @@ int getList(void) { return numSfiles; } +int getList(void) { + // No change since last call? + // TODO/FIXME: Just always reload this data? Be careful about slow downs!!! + if (!NeedLoad) + return numSfiles; + + return getList(_vm->getSaveFileMan(), _vm->getTargetName()); +} + char *ListEntry(int i, letype which) { if (i == -1) diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index e2a24dbd47..e37c80ec61 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -74,7 +74,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound assert(id > 0 && id < _sampleIndexLen); // get file offset for this sample - uint32 dwSampleIndex = _sampleIndex[id]; + int32 dwSampleIndex = _sampleIndex[id]; // move to correct position in the sample file _sampleStream.seek(dwSampleIndex); @@ -166,7 +166,7 @@ void SoundManager::openSampleFiles(void) { if (_sampleIndex == NULL) { // allocate a buffer for the indices - _sampleIndex = (uint32 *)malloc(_sampleIndexLen); + _sampleIndex = (int32 *)malloc(_sampleIndexLen); // make sure memory allocated if (_sampleIndex == NULL) { diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h index 56618eeb8e..330409cf59 100644 --- a/engines/tinsel/sound.h +++ b/engines/tinsel/sound.h @@ -37,7 +37,6 @@ namespace Tinsel { -#define MAXSAMPVOL 127 /*----------------------------------------------------------------------*\ |* Function Prototypes *| @@ -52,7 +51,7 @@ protected: Audio::SoundHandle _handle; /** Sample index buffer and number of entries */ - uint32 *_sampleIndex; + int32 *_sampleIndex; /** Number of entries in the sample index */ long _sampleIndexLen; diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index e8364e20dd..07c1b22b2a 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -1271,7 +1271,7 @@ void printtag(HPOLYGON hp, SCNHANDLE text) { void quitgame(void) { stopmidi(); stopsample(); - _vm->quitFlag = true; + _vm->quitGame(); } /** @@ -1991,7 +1991,6 @@ void topplay(CORO_PARAM, SCNHANDLE film, int x, int y, int complete, int actorid /** * Open or close the 'top window' */ - void topwindow(int bpos) { assert(bpos == TW_START || bpos == TW_END); @@ -2010,7 +2009,6 @@ void topwindow(int bpos) { /** * unhookscene */ - void unhookscene(void) { UnHookScene(); } @@ -2018,7 +2016,6 @@ void unhookscene(void) { /** * Un-define an actor as tagged. */ - void untagactor(int actor) { UnTagActor(actor); } @@ -2026,14 +2023,12 @@ void untagactor(int actor) { /** * vibrate */ - void vibrate(void) { } /** * waitframe(int actor, int frameNumber) */ - void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); @@ -2056,7 +2051,6 @@ void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEven /** * Return when a key pressed or button pushed. */ - void waitkey(CORO_PARAM, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; int startEvent; @@ -2104,7 +2098,6 @@ void waitkey(CORO_PARAM, bool escOn, int myescEvent) { /** * Pause for requested time. */ - void waittime(CORO_PARAM, int time, bool frame, bool escOn, int myescEvent) { CORO_BEGIN_CONTEXT; int time; @@ -2261,7 +2254,6 @@ void walkingactor(uint32 id, SCNHANDLE *rp) { * Walk a moving actor towards the polygon's tag, but return when the * actor enters the polygon. */ - void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { // COROUTINE CORO_BEGIN_CONTEXT; @@ -2309,7 +2301,6 @@ void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, in /** * walktag(actor, reel, hold) */ - void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) { // COROUTINE CORO_BEGIN_CONTEXT; @@ -2385,7 +2376,6 @@ void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int /** * whichinventory */ - int whichinventory(void) { return WhichInventoryOpen(); } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 1f56385283..7fb949704a 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -206,13 +206,16 @@ void KeyboardProcess(CORO_PARAM, const void *) { { int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0; int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset; - if ((language == TXT_GERMAN) && +#if 0 // FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922). + if ((g_language == TXT_GERMAN) && ((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) { // Skip to title screen // It seems the German CD version uses scenes 25,26,27,17 for the intro, // instead of 13,14,15,11; also, the title screen is 11 instead of 10 SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); - } else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { + } else +#endif + if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { // Skip to title screen SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); } else { @@ -622,11 +625,11 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); //bool adlib = (midiDriver == MD_ADLIB); - MidiDriver *driver = MidiDriver::createMidi(midiDriver); + _driver = MidiDriver::createMidi(midiDriver); if (native_mt32) - driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - _music = new MusicPlayer(driver); + _music = new MusicPlayer(_driver); //_music->setNativeMT32(native_mt32); //_music->setAdlib(adlib); @@ -638,13 +641,14 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) _mousePos.y = 0; _keyHandler = NULL; _dosPlayerDir = 0; - quitFlag = false; } TinselEngine::~TinselEngine() { delete _sound; delete _music; delete _console; + delete _driver; + _screenSurface.free(); FreeSs(); FreeTextBuffer(); FreeHandleTable(); @@ -678,6 +682,8 @@ int TinselEngine::init() { #if 1 // FIXME: The following is taken from RestartGame(). // It may have to be adjusted a bit + CountOut = 1; + RebootCursor(); RebootDeadTags(); RebootMovers(); @@ -692,25 +698,8 @@ int TinselEngine::init() { // TODO: More stuff from dos_main.c may have to be added here - // Set language - we'll be clever here and use the ScummVM language setting - language = TXT_ENGLISH; - switch (getLanguage()) { - case Common::FR_FRA: - language = TXT_FRENCH; - break; - case Common::DE_DEU: - language = TXT_GERMAN; - break; - case Common::IT_ITA: - language = TXT_ITALIAN; - break; - case Common::ES_ESP: - language = TXT_SPANISH; - break; - default: - language = TXT_ENGLISH; - } - ChangeLanguage(language); + // load in text strings + ChangeLanguage(g_language); // load in graphics info SetupHandleTable(); @@ -721,10 +710,6 @@ int TinselEngine::init() { return 0; } -Common::String TinselEngine::getSavegamePattern() const { - return _targetName + ".???"; -} - Common::String TinselEngine::getSavegameFilename(int16 saveNum) const { char filename[256]; snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum); @@ -755,7 +740,7 @@ int TinselEngine::go() { // Foreground loop - while (!quitFlag) { + while (!quit()) { assert(_console); if (_console->isAttached()) _console->onFrame(); @@ -819,10 +804,6 @@ bool TinselEngine::pollEvent() { // Handle the various kind of events switch (event.type) { - case Common::EVENT_QUIT: - quitFlag = true; - break; - case Common::EVENT_LBUTTONDOWN: case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONDOWN: diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h index 44cc83af9b..9820be7ddd 100644 --- a/engines/tinsel/tinsel.h +++ b/engines/tinsel/tinsel.h @@ -55,12 +55,19 @@ enum TinselGameFeatures { GF_DEMO = 1 << 0, GF_CD = 1 << 1, GF_FLOPPY = 1 << 2, - GF_SCNFILES = 1 << 3 + GF_SCNFILES = 1 << 3, + + // The GF_USE_?FLAGS values specify how many country flags are displayed + // in the subtitles options dialog. + // None of these defined -> 1 language, in ENGLISH.TXT + GF_USE_3FLAGS = 1 << 4, // French, German, Spanish + GF_USE_4FLAGS = 1 << 5, // French, German, Spanish, Italian + GF_USE_5FLAGS = 1 << 6 // All 5 flags }; enum TinselEngineVersion { - TINSEL_V0 = 1 << 0, // Used in the DW1 demo only - TINSEL_V1 = 1 << 1 + TINSEL_V0 = 0, // Used in the DW1 demo only + TINSEL_V1 = 1 }; struct TinselGameDescription; @@ -72,7 +79,7 @@ enum TinselKeyDirection { typedef bool (*KEYFPTR)(const Common::KeyState &); -class TinselEngine : public ::Engine { +class TinselEngine : public Engine { int _gameId; Common::KeyState _keyPressed; Common::RandomSource _random; @@ -100,8 +107,8 @@ public: Common::Language getLanguage() const; uint16 getVersion() const; Common::Platform getPlatform() const; - bool quitFlag; + MidiDriver *_driver; SoundManager *_sound; MusicPlayer *_music; @@ -120,7 +127,6 @@ private: public: const Common::String getTargetName() const { return _targetName; } - Common::String getSavegamePattern() const; Common::String getSavegameFilename(int16 saveNum) const; Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; } Graphics::Surface &screen() { return _screenSurface; } diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp index d2798d7060..bbc605ba46 100644 --- a/engines/touche/detection.cpp +++ b/engines/touche/detection.cpp @@ -25,6 +25,7 @@ #include "common/config-manager.h" #include "common/advancedDetector.h" +#include "common/savefile.h" #include "base/plugins.h" @@ -135,9 +136,20 @@ public: return "Touche: The Adventures of the 5th Musketeer (C) Clipper Software"; } + virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const; + virtual SaveStateList listSaves(const char *target) const; + virtual void removeSaveState(const char *target, int slot) const; }; +bool ToucheMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsListSaves) || + (f == kSupportsDirectLoad) || + (f == kSupportsDeleteSave); +} + bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const { const Common::ADGameDescription *gd = desc; if (gd) { @@ -146,6 +158,67 @@ bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm return gd != 0; } +SaveStateList ToucheMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringList filenames; + char saveDesc[Touche::kGameStateDescriptionLen]; + Common::String pattern = target; + pattern += ".?"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last digit of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 1); + + if (slotNum >= 0 && slotNum <= 9) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + in->readUint16LE(); + in->readUint16LE(); + in->read(saveDesc, Touche::kGameStateDescriptionLen); + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + delete in; + } + } + } + + pattern += "?"; + + filenames = saveFileMan->listSavefiles(pattern.c_str()); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + // Obtain the last 2 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 2); + + if (slotNum >= 10 && slotNum <= 99) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + in->readUint16LE(); + in->readUint16LE(); + in->read(saveDesc, Touche::kGameStateDescriptionLen); + saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file)); + delete in; + } + } + } + + return saveList; +} + +void ToucheMetaEngine::removeSaveState(const char *target, int slot) const { + char extension[5]; + snprintf(extension, sizeof(extension), ".%d", slot); + + Common::String filename = target; + filename += extension; + + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} + #if PLUGIN_ENABLED_DYNAMIC(TOUCHE) REGISTER_PLUGIN_DYNAMIC(TOUCHE, PLUGIN_TYPE_ENGINE, ToucheMetaEngine); #else diff --git a/engines/touche/menu.cpp b/engines/touche/menu.cpp index 6d2d90a572..82490fca38 100644 --- a/engines/touche/menu.cpp +++ b/engines/touche/menu.cpp @@ -297,7 +297,7 @@ void ToucheEngine::handleMenuAction(void *menu, int actionId) { menuData->quit = true; break; case kActionQuitGame: - _flagsTable[611] = 1; + quitGame(); menuData->quit = true; break; case kActionTextOnly: @@ -395,10 +395,10 @@ void ToucheEngine::handleOptions(int forceDisplay) { while (_eventMan->pollEvent(event)) { const Button *button = 0; switch (event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: menuData.quit = true; menuData.exit = true; - _flagsTable[611] = 1; break; case Common::EVENT_LBUTTONDOWN: button = menuData.findButtonUnderCursor(event.mouse.x, event.mouse.y); @@ -433,8 +433,9 @@ void ToucheEngine::handleOptions(int forceDisplay) { _system->delayMillis(10); } _fullRedrawCounter = 2; - if (!menuData.exit && _flagsTable[611] != 0) { - _flagsTable[611] = displayQuitDialog(); + if (!menuData.exit && quit()) { + if (displayQuitDialog()) + quitGame(); } } } @@ -556,6 +557,7 @@ int ToucheEngine::displayQuitDialog() { Common::Event event; while (_eventMan->pollEvent(event)) { switch (event.type) { + case Common::EVENT_RTL: case Common::EVENT_QUIT: quitLoop = true; ret = 1; diff --git a/engines/touche/opcodes.cpp b/engines/touche/opcodes.cpp index 4405c614ac..b2b16eb29d 100644 --- a/engines/touche/opcodes.cpp +++ b/engines/touche/opcodes.cpp @@ -408,6 +408,10 @@ void ToucheEngine::op_setFlag() { case 104: _currentKeyCharNum = val; break; + case 611: + if (val != 0) + quitGame(); + break; case 612: _flagsTable[613] = getRandomNumber(val); break; diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp index 4fcf6e114d..fedd40eb76 100644 --- a/engines/touche/saveload.cpp +++ b/engines/touche/saveload.cpp @@ -31,11 +31,6 @@ namespace Touche { -enum { - kCurrentGameStateVersion = 6, - kGameStateDescriptionLen = 32 -}; - static void saveOrLoad(Common::WriteStream &stream, uint16 &i) { stream.writeUint16LE(i); } @@ -292,7 +287,7 @@ void ToucheEngine::loadGameStateData(Common::ReadStream *stream) { if (stream->readUint32LE() != saveLoadEndMarker) { warning("Corrupted gamestate data"); // if that ever happens, exit the game - _flagsTable[611] = 1; + quitGame(); } _flagsTable[614] = roomOffsX; _flagsTable[615] = roomOffsY; diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index a39517fe32..e122187dcd 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -95,7 +95,7 @@ int ToucheEngine::init() { _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); return 0; } @@ -234,6 +234,13 @@ Common::Point ToucheEngine::getMousePos() const { return _eventMan->getMousePos(); } +void ToucheEngine::syncSoundSettings() { + readConfigurationSettings(); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); +} + void ToucheEngine::mainLoop() { restart(); @@ -245,10 +252,13 @@ void ToucheEngine::mainLoop() { _inp_rightMouseButtonPressed = false; if (ConfMan.hasKey("save_slot")) { - loadGameState(ConfMan.getInt("save_slot")); - _newEpisodeNum = 0; - resetSortedKeyCharsTable(); - showCursor(true); + int saveSlot = ConfMan.getInt("save_slot"); + if (saveSlot >= 0 && saveSlot <= 99) { + loadGameState(saveSlot); + _newEpisodeNum = 0; + resetSortedKeyCharsTable(); + showCursor(true); + } } else { _newEpisodeNum = ConfMan.getInt("boot_param"); if (_newEpisodeNum == 0) { @@ -258,7 +268,7 @@ void ToucheEngine::mainLoop() { } uint32 frameTimeStamp = _system->getMillis(); - for (uint32 cycleCounter = 0; _flagsTable[611] == 0; ++cycleCounter) { + for (uint32 cycleCounter = 0; !quit(); ++cycleCounter) { if ((cycleCounter % 3) == 0) { runCycle(); } @@ -287,9 +297,6 @@ void ToucheEngine::processEvents(bool handleKeyEvents) { Common::Event event; while (_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_QUIT: - _flagsTable[611] = 1; - break; case Common::EVENT_KEYDOWN: if (!handleKeyEvents) { break; @@ -297,7 +304,8 @@ void ToucheEngine::processEvents(bool handleKeyEvents) { _flagsTable[600] = event.kbd.keycode; if (event.kbd.keycode == Common::KEYCODE_ESCAPE) { if (_displayQuitDialog) { - _flagsTable[611] = displayQuitDialog(); + if (displayQuitDialog()) + quitGame(); } } else if (event.kbd.keycode == Common::KEYCODE_F5) { if (_flagsTable[618] == 0 && !_hideInventoryTexts) { @@ -1829,7 +1837,7 @@ int ToucheEngine::handleActionMenuUnderCursor(const int16 *actions, int offs, in _menuRedrawCounter = 2; Common::Rect rect(0, y, kScreenWidth, y + h); i = -1; - while (_inp_rightMouseButtonPressed && _flagsTable[611] == 0) { + while (_inp_rightMouseButtonPressed && !quit()) { Common::Point mousePos = getMousePos(); if (rect.contains(mousePos)) { int c = (mousePos.y - y) / kTextHeight; @@ -2692,10 +2700,10 @@ bool ToucheEngine::sortPointsData(int num1, int num2) { const int md2 = _programWalkTable[num1].point2; _programPointsTable[md2].order = 0; } - bool quit = false; + bool quitLoop = false; int order = 1; - while (!quit) { - quit = true; + while (!quitLoop) { + quitLoop = true; for (uint i = 0; i < _programWalkTable.size(); ++i) { const int md1 = _programWalkTable[i].point1; const int md2 = _programWalkTable[i].point2; @@ -2703,11 +2711,11 @@ bool ToucheEngine::sortPointsData(int num1, int num2) { assert((md2 & 0x4000) == 0); if (_programPointsTable[md1].order == order - 1 && _programPointsTable[md2].order > order) { _programPointsTable[md2].order = order; - quit = false; + quitLoop = false; } if (_programPointsTable[md2].order == order - 1 && _programPointsTable[md1].order > order) { _programPointsTable[md1].order = order; - quit = false; + quitLoop = false; } } } @@ -2939,9 +2947,9 @@ void ToucheEngine::markWalkPoints(int keyChar) { resetPointsData(0); if (pointsDataNum != -1) { _programPointsTable[pointsDataNum].order = 1; - bool quit = false; - while (!quit) { - quit = true; + bool quitLoop = false; + while (!quitLoop) { + quitLoop = true; for (uint i = 0; i < _programWalkTable.size(); ++i) { int16 md1 = _programWalkTable[i].point1; int16 md2 = _programWalkTable[i].point2; @@ -2949,11 +2957,11 @@ void ToucheEngine::markWalkPoints(int keyChar) { assert((md2 & 0x4000) == 0); if (_programPointsTable[md1].order != 0 && _programPointsTable[md2].order == 0) { _programPointsTable[md2].order = 1; - quit = false; + quitLoop = false; } if (_programPointsTable[md2].order != 0 && _programPointsTable[md1].order == 0) { _programPointsTable[md1].order = 1; - quit = false; + quitLoop = false; } } } diff --git a/engines/touche/touche.h b/engines/touche/touche.h index 41f5c832c5..f341769422 100644 --- a/engines/touche/touche.h +++ b/engines/touche/touche.h @@ -328,7 +328,9 @@ enum { kCursorHeight = 42, kTextHeight = 16, kMaxProgramDataSize = 61440, - kMaxSaveStates = 100 + kMaxSaveStates = 100, + kGameStateDescriptionLen = 32, // Need these two values defined here + kCurrentGameStateVersion = 6 // for --list-saves support }; enum StringType { @@ -361,6 +363,7 @@ public: virtual int init(); virtual int go(); + virtual void syncSoundSettings(); protected: |
