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/kyra | |
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/kyra')
55 files changed, 3947 insertions, 2709 deletions
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; |