aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS22
-rw-r--r--COPYRIGHT47
-rw-r--r--NEWS18
-rw-r--r--README158
-rw-r--r--backends/events/default/default-events.cpp77
-rw-r--r--backends/events/default/default-events.h4
-rw-r--r--backends/fs/abstract-fs.cpp40
-rw-r--r--backends/fs/abstract-fs.h61
-rw-r--r--backends/fs/amigaos4/amigaos4-fs-factory.cpp4
-rw-r--r--backends/fs/amigaos4/amigaos4-fs-factory.h13
-rw-r--r--backends/fs/amigaos4/amigaos4-fs.cpp49
-rw-r--r--backends/fs/ds/ds-fs-factory.cpp2
-rw-r--r--backends/fs/ds/ds-fs-factory.h4
-rw-r--r--backends/fs/ds/ds-fs.cpp250
-rw-r--r--backends/fs/ds/ds-fs.h47
-rw-r--r--backends/fs/palmos/palmos-fs-factory.cpp2
-rw-r--r--backends/fs/palmos/palmos-fs-factory.h4
-rw-r--r--backends/fs/palmos/palmos-fs.cpp72
-rw-r--r--backends/fs/posix/posix-fs-factory.cpp11
-rw-r--r--backends/fs/posix/posix-fs-factory.h14
-rw-r--r--backends/fs/posix/posix-fs.cpp216
-rw-r--r--backends/fs/posix/posix-fs.h86
-rw-r--r--backends/fs/ps2/ps2-fs-factory.cpp2
-rw-r--r--backends/fs/ps2/ps2-fs-factory.h4
-rw-r--r--backends/fs/ps2/ps2-fs.cpp73
-rw-r--r--backends/fs/psp/psp-fs-factory.cpp2
-rw-r--r--backends/fs/psp/psp-fs-factory.h4
-rw-r--r--backends/fs/psp/psp-fs.cpp64
-rw-r--r--backends/fs/stdiostream.cpp161
-rw-r--r--backends/fs/stdiostream.h (renamed from engines/scumm/smush/chunk.h)76
-rw-r--r--backends/fs/symbian/symbian-fs-factory.cpp4
-rw-r--r--backends/fs/symbian/symbian-fs-factory.h13
-rw-r--r--backends/fs/symbian/symbian-fs.cpp162
-rw-r--r--backends/fs/symbian/symbianstream.cpp274
-rw-r--r--backends/fs/symbian/symbianstream.h62
-rw-r--r--backends/fs/wii/wii-fs-factory.cpp2
-rw-r--r--backends/fs/wii/wii-fs-factory.h4
-rw-r--r--backends/fs/wii/wii-fs.cpp70
-rw-r--r--backends/fs/windows/windows-fs-factory.cpp4
-rw-r--r--backends/fs/windows/windows-fs-factory.h13
-rw-r--r--backends/fs/windows/windows-fs.cpp94
-rw-r--r--backends/midi/alsa.cpp42
-rw-r--r--backends/midi/seq.cpp2
-rw-r--r--backends/midi/stmidi.cpp155
-rw-r--r--backends/module.mk3
-rw-r--r--backends/platform/PalmOS/Src/be_base.cpp5
-rw-r--r--backends/platform/dc/dc-fs.cpp77
-rw-r--r--backends/platform/dc/selector.cpp14
-rw-r--r--backends/platform/dc/vmsave.cpp26
-rw-r--r--backends/platform/ds/arm7/Makefile2
-rw-r--r--backends/platform/ds/arm7/source/main.cpp5
-rw-r--r--backends/platform/ds/arm9/dist/readme_ds.txt840
-rw-r--r--backends/platform/ds/arm9/makefile90
-rw-r--r--backends/platform/ds/arm9/source/blitters_arm.s137
-rw-r--r--backends/platform/ds/arm9/source/cdaudio.h2
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp709
-rw-r--r--backends/platform/ds/arm9/source/dsmain.h13
-rw-r--r--backends/platform/ds/arm9/source/dsoptions.cpp283
-rw-r--r--backends/platform/ds/arm9/source/dsoptions.h13
-rw-r--r--backends/platform/ds/arm9/source/gbampsave.cpp43
-rw-r--r--backends/platform/ds/arm9/source/gbampsave.h8
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.cpp232
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.h26
-rw-r--r--backends/platform/ds/arm9/source/portdefs.h5
-rw-r--r--backends/platform/ds/arm9/source/ramsave.cpp30
-rw-r--r--backends/platform/ds/arm9/source/ramsave.h14
-rw-r--r--backends/platform/ds/arm9/source/touchkeyboard.cpp30
-rw-r--r--backends/platform/ds/arm9/source/touchkeyboard.h1
-rw-r--r--backends/platform/ds/logog.bmpbin0 -> 630 bytes
-rw-r--r--backends/platform/ds/makefile20
-rw-r--r--backends/platform/gp2x/gp2x.cpp2
-rw-r--r--backends/platform/iphone/iphone_keyboard.m3
-rw-r--r--backends/platform/iphone/iphone_main.m13
-rw-r--r--backends/platform/iphone/iphone_video.m14
-rw-r--r--backends/platform/iphone/osys_iphone.cpp759
-rw-r--r--backends/platform/iphone/osys_iphone.h31
-rw-r--r--backends/platform/null/null.cpp29
-rw-r--r--backends/platform/ps2/rawsavefile.cpp13
-rw-r--r--backends/platform/ps2/rawsavefile.h3
-rw-r--r--backends/platform/ps2/savefile.cpp59
-rw-r--r--backends/platform/ps2/savefile.h37
-rw-r--r--backends/platform/psp/osys_psp.cpp15
-rw-r--r--backends/platform/psp/osys_psp_gu.cpp14
-rw-r--r--backends/platform/psp/portdefs.h1
-rw-r--r--backends/platform/psp/psp_main.cpp10
-rw-r--r--backends/platform/sdl/events.cpp2
-rw-r--r--backends/platform/sdl/graphics.cpp19
-rw-r--r--backends/platform/sdl/sdl.cpp208
-rw-r--r--backends/platform/sdl/sdl.h7
-rw-r--r--backends/platform/symbian/AdaptAllMMPs.pl16
-rw-r--r--backends/platform/symbian/BuildPackageUpload_AllVersions.pl10
-rw-r--r--backends/platform/symbian/BuildPackageUpload_LocalSettings.pl81
-rw-r--r--backends/platform/symbian/README37
-rw-r--r--backends/platform/symbian/S60/ScummVM_S60.mmp.in1
-rw-r--r--backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg4
-rw-r--r--backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg3
-rw-r--r--backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in3
-rw-r--r--backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg5
-rw-r--r--backends/platform/symbian/S80/ScummVM_S80.mmp.in1
-rw-r--r--backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg3
-rw-r--r--backends/platform/symbian/S90/Scummvm_S90.mmp.in1
-rw-r--r--backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg3
-rw-r--r--backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in1
-rw-r--r--backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg4
-rw-r--r--backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg2
-rw-r--r--backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in3
-rw-r--r--backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg5
-rw-r--r--backends/platform/symbian/mmp/scummvm_base.mmp.in8
-rw-r--r--backends/platform/symbian/mmp/scummvm_tinsel.mmp.in56
-rw-r--r--backends/platform/symbian/src/SymbianActions.cpp20
-rw-r--r--backends/platform/symbian/src/SymbianOS.cpp283
-rw-r--r--backends/platform/symbian/src/SymbianOS.h14
-rw-r--r--backends/platform/symbian/src/main_features.inl93
-rw-r--r--backends/platform/symbian/src/portdefs.h43
-rw-r--r--backends/platform/symbian/src/vsnprintf.h668
-rw-r--r--backends/platform/wii/Makefile99
-rw-r--r--backends/platform/wii/gx_supp.cpp47
-rw-r--r--backends/platform/wii/gx_supp.h7
-rw-r--r--backends/platform/wii/main.cpp4
-rw-r--r--backends/platform/wii/osystem.cpp34
-rw-r--r--backends/platform/wii/osystem.h7
-rw-r--r--backends/platform/wii/osystem_gfx.cpp75
-rw-r--r--backends/platform/wince/CEActionsPocket.cpp21
-rw-r--r--backends/platform/wince/CEActionsSmartphone.cpp21
-rw-r--r--backends/platform/wince/CELauncherDialog.cpp12
-rw-r--r--backends/platform/wince/CELauncherDialog.h2
-rw-r--r--backends/platform/wince/CEkeys/EventsBuffer.cpp3
-rw-r--r--backends/platform/wince/Makefile10
-rw-r--r--backends/platform/wince/README-WinCE.txt189
-rw-r--r--backends/platform/wince/missing/missing.cpp11
-rw-r--r--backends/platform/wince/wince-sdl.cpp35
-rw-r--r--backends/platform/wince/wince-sdl.h1
-rw-r--r--backends/saves/compressed/compressed-saves.cpp270
-rw-r--r--backends/saves/default/default-saves.cpp154
-rw-r--r--backends/saves/default/default-saves.h6
-rw-r--r--backends/vkeybd/virtual-keyboard.cpp27
-rw-r--r--base/commandLine.cpp63
-rw-r--r--base/main.cpp54
-rw-r--r--base/module.mk1
-rw-r--r--base/plugins.cpp28
-rw-r--r--base/plugins.h9
-rw-r--r--base/version.cpp11
-rw-r--r--common/advancedDetector.cpp230
-rw-r--r--common/advancedDetector.h7
-rw-r--r--common/archive.cpp344
-rw-r--r--common/archive.h231
-rw-r--r--common/array.h66
-rw-r--r--common/config-file.cpp68
-rw-r--r--common/config-manager.cpp376
-rw-r--r--common/config-manager.h12
-rw-r--r--common/events.h19
-rw-r--r--common/file.cpp435
-rw-r--r--common/file.h50
-rw-r--r--common/fs.cpp41
-rw-r--r--common/fs.h97
-rw-r--r--common/func.h119
-rw-r--r--common/hash-str.h4
-rw-r--r--common/hashmap.cpp116
-rw-r--r--common/hashmap.h282
-rw-r--r--common/iff_container.h16
-rw-r--r--common/keyboard.h2
-rw-r--r--common/md5.cpp11
-rw-r--r--common/md5.h5
-rw-r--r--common/memorypool.cpp111
-rw-r--r--common/memorypool.h45
-rw-r--r--common/module.mk1
-rw-r--r--common/ptr.h4
-rw-r--r--common/queue.h51
-rw-r--r--common/savefile.h17
-rw-r--r--common/str.cpp265
-rw-r--r--common/str.h109
-rw-r--r--common/stream.cpp94
-rw-r--r--common/stream.h211
-rw-r--r--common/system.cpp62
-rw-r--r--common/system.h32
-rw-r--r--common/unarj.cpp355
-rw-r--r--common/unarj.h83
-rw-r--r--common/unzip.cpp537
-rw-r--r--common/unzip.h290
-rw-r--r--common/util.cpp50
-rw-r--r--common/util.h31
-rw-r--r--common/xmlparser.cpp71
-rw-r--r--common/xmlparser.h240
-rw-r--r--common/zlib.cpp308
-rw-r--r--common/zlib.h57
-rwxr-xr-xconfigure10
-rw-r--r--dists/engine-data/drascula.datbin213737 -> 218411 bytes
-rw-r--r--dists/engine-data/kyra.datbin236767 -> 242675 bytes
-rw-r--r--dists/macosx/Info.plist.in4
-rw-r--r--dists/msvc7/agi.vcproj15
-rw-r--r--dists/msvc7/agos.vcproj17
-rw-r--r--dists/msvc7/cine.vcproj17
-rw-r--r--dists/msvc7/cruise.vcproj20
-rw-r--r--dists/msvc7/drascula.vcproj15
-rw-r--r--dists/msvc7/gob.vcproj26
-rw-r--r--dists/msvc7/igor.vcproj15
-rw-r--r--dists/msvc7/kyra.vcproj35
-rw-r--r--dists/msvc7/lure.vcproj17
-rw-r--r--dists/msvc7/m4.vcproj15
-rw-r--r--dists/msvc7/made.vcproj15
-rw-r--r--dists/msvc7/parallaction.vcproj18
-rw-r--r--dists/msvc7/queen.vcproj17
-rw-r--r--dists/msvc7/saga.vcproj19
-rw-r--r--dists/msvc7/scumm.vcproj26
-rw-r--r--dists/msvc7/scummvm.vcproj66
-rw-r--r--dists/msvc7/sky.vcproj17
-rw-r--r--dists/msvc7/sword1.vcproj17
-rw-r--r--dists/msvc7/sword2.vcproj17
-rw-r--r--dists/msvc7/tinsel.vcproj349
-rw-r--r--dists/msvc7/touche.vcproj15
-rw-r--r--dists/msvc71/agi.vcproj15
-rw-r--r--dists/msvc71/agos.vcproj17
-rw-r--r--dists/msvc71/cine.vcproj17
-rw-r--r--dists/msvc71/cruise.vcproj20
-rw-r--r--dists/msvc71/drascula.vcproj15
-rw-r--r--dists/msvc71/gob.vcproj26
-rw-r--r--dists/msvc71/igor.vcproj15
-rw-r--r--dists/msvc71/kyra.vcproj35
-rw-r--r--dists/msvc71/lure.vcproj17
-rw-r--r--dists/msvc71/m4.vcproj15
-rw-r--r--dists/msvc71/made.vcproj15
-rw-r--r--dists/msvc71/parallaction.vcproj18
-rw-r--r--dists/msvc71/queen.vcproj17
-rw-r--r--dists/msvc71/saga.vcproj19
-rw-r--r--dists/msvc71/scumm.vcproj26
-rw-r--r--dists/msvc71/scummvm.vcproj66
-rw-r--r--dists/msvc71/sky.vcproj17
-rw-r--r--dists/msvc71/sword1.vcproj17
-rw-r--r--dists/msvc71/sword2.vcproj17
-rw-r--r--dists/msvc71/tinsel.vcproj363
-rw-r--r--dists/msvc71/touche.vcproj15
-rw-r--r--dists/msvc8/agi.vcproj10
-rw-r--r--dists/msvc8/agos.vcproj14
-rw-r--r--dists/msvc8/cine.vcproj14
-rw-r--r--dists/msvc8/cruise.vcproj18
-rw-r--r--dists/msvc8/drascula.vcproj10
-rw-r--r--dists/msvc8/gob.vcproj28
-rw-r--r--dists/msvc8/igor.vcproj10
-rw-r--r--dists/msvc8/kyra.vcproj38
-rw-r--r--dists/msvc8/lure.vcproj14
-rw-r--r--dists/msvc8/m4.vcproj10
-rw-r--r--dists/msvc8/made.vcproj10
-rw-r--r--dists/msvc8/parallaction.vcproj14
-rw-r--r--dists/msvc8/queen.vcproj14
-rw-r--r--dists/msvc8/saga.vcproj16
-rw-r--r--dists/msvc8/scumm.vcproj25
-rw-r--r--dists/msvc8/scummvm.vcproj74
-rw-r--r--dists/msvc8/sky.vcproj13
-rw-r--r--dists/msvc8/sword1.vcproj14
-rw-r--r--dists/msvc8/sword2.vcproj14
-rw-r--r--dists/msvc8/tinsel.vcproj12
-rw-r--r--dists/msvc8/touche.vcproj10
-rw-r--r--dists/msvc8_to_msvc7_71.bat8
-rw-r--r--dists/msvc9/agi.vcproj10
-rw-r--r--dists/msvc9/agos.vcproj14
-rw-r--r--dists/msvc9/cine.vcproj14
-rw-r--r--dists/msvc9/cruise.vcproj18
-rw-r--r--dists/msvc9/drascula.vcproj10
-rw-r--r--dists/msvc9/gob.vcproj28
-rw-r--r--dists/msvc9/igor.vcproj10
-rw-r--r--dists/msvc9/kyra.vcproj38
-rw-r--r--dists/msvc9/lure.vcproj14
-rw-r--r--dists/msvc9/m4.vcproj10
-rw-r--r--dists/msvc9/made.vcproj10
-rw-r--r--dists/msvc9/parallaction.vcproj14
-rw-r--r--dists/msvc9/queen.vcproj14
-rw-r--r--dists/msvc9/saga.vcproj16
-rw-r--r--dists/msvc9/scumm.vcproj25
-rw-r--r--dists/msvc9/scummvm.vcproj78
-rw-r--r--dists/msvc9/sky.vcproj13
-rw-r--r--dists/msvc9/sword1.vcproj14
-rw-r--r--dists/msvc9/sword2.vcproj14
-rw-r--r--dists/msvc9/tinsel.vcproj12
-rw-r--r--dists/msvc9/touche.vcproj10
-rw-r--r--dists/redhat/scummvm-tools.spec10
-rw-r--r--dists/scummvm.621
-rw-r--r--dists/scummvm.rc2
-rw-r--r--dists/scummvm.rc.in2
-rw-r--r--dists/wii/READMII43
-rw-r--r--engines/agi/agi.cpp16
-rw-r--r--engines/agi/agi.h5
-rw-r--r--engines/agi/cycle.cpp16
-rw-r--r--engines/agi/detection.cpp67
-rw-r--r--engines/agi/loader_v3.cpp12
-rw-r--r--engines/agi/op_cmd.cpp8
-rw-r--r--engines/agi/op_test.cpp3
-rw-r--r--engines/agi/preagi.cpp1
-rw-r--r--engines/agi/preagi.h2
-rw-r--r--engines/agi/preagi_common.cpp7
-rw-r--r--engines/agi/preagi_mickey.cpp29
-rw-r--r--engines/agi/preagi_mickey.h6
-rw-r--r--engines/agi/preagi_troll.cpp11
-rw-r--r--engines/agi/preagi_winnie.cpp9
-rw-r--r--engines/agi/saveload.cpp25
-rw-r--r--engines/agi/sound.cpp41
-rw-r--r--engines/agi/sound.h1
-rw-r--r--engines/agi/wagparser.h4
-rw-r--r--engines/agos/agos.cpp43
-rw-r--r--engines/agos/agos.h3
-rw-r--r--engines/agos/animation.cpp8
-rw-r--r--engines/agos/detection.cpp41
-rw-r--r--engines/agos/event.cpp6
-rw-r--r--engines/agos/gfx.cpp2
-rw-r--r--engines/agos/input.cpp18
-rw-r--r--engines/agos/midi.cpp62
-rw-r--r--engines/agos/midi.h7
-rw-r--r--engines/agos/oracle.cpp2
-rw-r--r--engines/agos/res.cpp3
-rw-r--r--engines/agos/saveload.cpp30
-rw-r--r--engines/agos/script.cpp10
-rw-r--r--engines/agos/script_e1.cpp13
-rw-r--r--engines/agos/script_e2.cpp4
-rw-r--r--engines/agos/script_s1.cpp15
-rw-r--r--engines/agos/script_ww.cpp4
-rw-r--r--engines/agos/sound.cpp13
-rw-r--r--engines/agos/subroutine.cpp2
-rw-r--r--engines/agos/verb.cpp3
-rw-r--r--engines/agos/window.cpp4
-rw-r--r--engines/cine/anim.cpp213
-rw-r--r--engines/cine/anim.h5
-rw-r--r--engines/cine/bg.cpp16
-rw-r--r--engines/cine/cine.cpp55
-rw-r--r--engines/cine/cine.h6
-rw-r--r--engines/cine/detection.cpp87
-rw-r--r--engines/cine/gfx.cpp202
-rw-r--r--engines/cine/gfx.h10
-rw-r--r--engines/cine/main_loop.cpp122
-rw-r--r--engines/cine/main_loop.h5
-rw-r--r--engines/cine/msg.cpp45
-rw-r--r--engines/cine/object.cpp9
-rw-r--r--engines/cine/object.h15
-rw-r--r--engines/cine/pal.cpp36
-rw-r--r--engines/cine/pal.h2
-rw-r--r--engines/cine/part.cpp80
-rw-r--r--engines/cine/part.h8
-rw-r--r--engines/cine/prc.cpp7
-rw-r--r--engines/cine/script_fw.cpp23
-rw-r--r--engines/cine/script_os.cpp24
-rw-r--r--engines/cine/sound.cpp15
-rw-r--r--engines/cine/texte.cpp196
-rw-r--r--engines/cine/texte.h31
-rw-r--r--engines/cine/unpack.cpp8
-rw-r--r--engines/cine/unpack.h6
-rw-r--r--engines/cine/various.cpp274
-rw-r--r--engines/cine/various.h12
-rw-r--r--engines/cruise/cruise_main.cpp2
-rw-r--r--engines/cruise/ctp.cpp14
-rw-r--r--engines/cruise/dataLoader.cpp21
-rw-r--r--engines/cruise/object.cpp4
-rw-r--r--engines/cruise/overlay.cpp312
-rw-r--r--engines/cruise/overlay.h2
-rw-r--r--engines/cruise/saveload.cpp3
-rw-r--r--engines/cruise/vars.h7
-rw-r--r--engines/cruise/volume.cpp4
-rw-r--r--engines/dialogs.cpp267
-rw-r--r--engines/dialogs.h77
-rw-r--r--engines/drascula/actors.cpp87
-rw-r--r--engines/drascula/animation.cpp800
-rw-r--r--engines/drascula/converse.cpp359
-rw-r--r--engines/drascula/detection.cpp32
-rw-r--r--engines/drascula/drascula.cpp196
-rw-r--r--engines/drascula/drascula.h195
-rw-r--r--engines/drascula/graphics.cpp201
-rw-r--r--engines/drascula/interface.cpp88
-rw-r--r--engines/drascula/objects.cpp30
-rw-r--r--engines/drascula/palette.cpp69
-rw-r--r--engines/drascula/rooms.cpp563
-rw-r--r--engines/drascula/saveload.cpp25
-rw-r--r--engines/drascula/sound.cpp59
-rw-r--r--engines/drascula/talk.cpp314
-rw-r--r--engines/engine.cpp62
-rw-r--r--engines/engine.h36
-rw-r--r--engines/game.cpp (renamed from base/game.cpp)49
-rw-r--r--engines/game.h (renamed from base/game.h)58
-rw-r--r--engines/gob/dataio.cpp22
-rw-r--r--engines/gob/dataio.h6
-rw-r--r--engines/gob/detection.cpp154
-rw-r--r--engines/gob/draw.cpp35
-rw-r--r--engines/gob/draw.h7
-rw-r--r--engines/gob/game_v1.cpp4
-rw-r--r--engines/gob/game_v2.cpp10
-rw-r--r--engines/gob/gob.cpp46
-rw-r--r--engines/gob/gob.h7
-rw-r--r--engines/gob/goblin.cpp74
-rw-r--r--engines/gob/inter.cpp4
-rw-r--r--engines/gob/inter.h96
-rw-r--r--engines/gob/inter_bargon.cpp6
-rw-r--r--engines/gob/inter_v1.cpp114
-rw-r--r--engines/gob/inter_v2.cpp3
-rw-r--r--engines/gob/inter_v5.cpp1040
-rw-r--r--engines/gob/inter_v6.cpp866
-rw-r--r--engines/gob/map.cpp6
-rw-r--r--engines/gob/map.h20
-rw-r--r--engines/gob/module.mk3
-rw-r--r--engines/gob/mult.cpp2
-rw-r--r--engines/gob/mult_v2.cpp9
-rw-r--r--engines/gob/palanim.cpp3
-rw-r--r--engines/gob/parse.h6
-rw-r--r--engines/gob/parse_v1.cpp2
-rw-r--r--engines/gob/parse_v2.cpp229
-rw-r--r--engines/gob/saveload.cpp2
-rw-r--r--engines/gob/sound/sound.cpp2
-rw-r--r--engines/gob/util.cpp10
-rw-r--r--engines/gob/video.h9
-rw-r--r--engines/gob/video_v6.cpp69
-rw-r--r--engines/gob/videoplayer.cpp3
-rw-r--r--engines/igor/parts/part_22.cpp6
-rw-r--r--engines/kyra/detection.cpp438
-rw-r--r--engines/kyra/gui.cpp5
-rw-r--r--engines/kyra/gui.h4
-rw-r--r--engines/kyra/gui_hof.cpp12
-rw-r--r--engines/kyra/gui_hof.h2
-rw-r--r--engines/kyra/gui_lok.cpp45
-rw-r--r--engines/kyra/gui_lok.h4
-rw-r--r--engines/kyra/gui_mr.cpp12
-rw-r--r--engines/kyra/gui_mr.h2
-rw-r--r--engines/kyra/gui_v2.cpp26
-rw-r--r--engines/kyra/gui_v2.h3
-rw-r--r--engines/kyra/kyra_hof.cpp76
-rw-r--r--engines/kyra/kyra_hof.h29
-rw-r--r--engines/kyra/kyra_lok.cpp31
-rw-r--r--engines/kyra/kyra_lok.h4
-rw-r--r--engines/kyra/kyra_mr.cpp25
-rw-r--r--engines/kyra/kyra_mr.h2
-rw-r--r--engines/kyra/kyra_v1.cpp36
-rw-r--r--engines/kyra/kyra_v1.h35
-rw-r--r--engines/kyra/kyra_v2.cpp10
-rw-r--r--engines/kyra/kyra_v2.h2
-rw-r--r--engines/kyra/lol.cpp802
-rw-r--r--engines/kyra/lol.h158
-rw-r--r--engines/kyra/module.mk3
-rw-r--r--engines/kyra/resource.cpp1380
-rw-r--r--engines/kyra/resource.h97
-rw-r--r--engines/kyra/resource_intern.cpp1072
-rw-r--r--engines/kyra/resource_intern.h132
-rw-r--r--engines/kyra/saveload.cpp60
-rw-r--r--engines/kyra/saveload_hof.cpp10
-rw-r--r--engines/kyra/saveload_lok.cpp12
-rw-r--r--engines/kyra/saveload_mr.cpp10
-rw-r--r--engines/kyra/scene_hof.cpp4
-rw-r--r--engines/kyra/scene_mr.cpp5
-rw-r--r--engines/kyra/screen.cpp57
-rw-r--r--engines/kyra/screen.h5
-rw-r--r--engines/kyra/screen_lok.cpp18
-rw-r--r--engines/kyra/screen_lok.h1
-rw-r--r--engines/kyra/screen_lol.cpp69
-rw-r--r--engines/kyra/screen_lol.h53
-rw-r--r--engines/kyra/screen_v2.cpp22
-rw-r--r--engines/kyra/screen_v2.h2
-rw-r--r--engines/kyra/script.cpp48
-rw-r--r--engines/kyra/script.h2
-rw-r--r--engines/kyra/script_lok.cpp3
-rw-r--r--engines/kyra/script_mr.cpp4
-rw-r--r--engines/kyra/script_tim.cpp391
-rw-r--r--engines/kyra/script_tim.h63
-rw-r--r--engines/kyra/sequences_hof.cpp251
-rw-r--r--engines/kyra/sequences_lok.cpp17
-rw-r--r--engines/kyra/sound.cpp17
-rw-r--r--engines/kyra/sound.h23
-rw-r--r--engines/kyra/sound_adlib.cpp29
-rw-r--r--engines/kyra/sound_towns.cpp2812
-rw-r--r--engines/kyra/sprites.cpp1
-rw-r--r--engines/kyra/staticres.cpp562
-rw-r--r--engines/kyra/text.cpp1
-rw-r--r--engines/kyra/text_hof.cpp12
-rw-r--r--engines/kyra/text_lok.cpp2
-rw-r--r--engines/kyra/text_mr.cpp10
-rw-r--r--engines/kyra/timer_mr.cpp2
-rw-r--r--engines/kyra/vqa.cpp143
-rw-r--r--engines/kyra/vqa.h4
-rw-r--r--engines/lure/animseq.cpp14
-rw-r--r--engines/lure/detection.cpp50
-rw-r--r--engines/lure/events.cpp16
-rw-r--r--engines/lure/events.h2
-rw-r--r--engines/lure/fights.cpp8
-rw-r--r--engines/lure/game.cpp29
-rw-r--r--engines/lure/game.h5
-rw-r--r--engines/lure/intro.cpp7
-rw-r--r--engines/lure/lure.cpp71
-rw-r--r--engines/lure/lure.h6
-rw-r--r--engines/lure/menu.cpp6
-rw-r--r--engines/lure/scripts.cpp6
-rw-r--r--engines/lure/sound.cpp32
-rw-r--r--engines/lure/sound.h4
-rw-r--r--engines/lure/surface.cpp14
-rw-r--r--engines/m4/converse.cpp45
-rw-r--r--engines/m4/globals.cpp14
-rw-r--r--engines/m4/m4.cpp6
-rw-r--r--engines/m4/mads_anim.cpp14
-rw-r--r--engines/m4/midi.cpp2
-rw-r--r--engines/m4/resource.cpp4
-rw-r--r--engines/made/detection.cpp4
-rw-r--r--engines/made/music.cpp2
-rw-r--r--engines/made/pmvplayer.cpp4
-rw-r--r--engines/made/redreader.cpp4
-rw-r--r--engines/made/screen.cpp19
-rw-r--r--engines/made/screenfx.cpp2
-rw-r--r--engines/metaengine.h103
-rw-r--r--engines/module.mk4
-rw-r--r--engines/parallaction/balloons.cpp601
-rw-r--r--engines/parallaction/callables_br.cpp2
-rw-r--r--engines/parallaction/callables_ns.cpp65
-rw-r--r--engines/parallaction/debug.cpp20
-rw-r--r--engines/parallaction/detection.cpp48
-rw-r--r--engines/parallaction/dialogue.cpp14
-rw-r--r--engines/parallaction/disk.h53
-rw-r--r--engines/parallaction/disk_br.cpp128
-rw-r--r--engines/parallaction/disk_ns.cpp26
-rw-r--r--engines/parallaction/exec.h2
-rw-r--r--engines/parallaction/exec_br.cpp111
-rw-r--r--engines/parallaction/exec_ns.cpp368
-rw-r--r--engines/parallaction/font.cpp2
-rw-r--r--engines/parallaction/gfxbase.cpp194
-rw-r--r--engines/parallaction/graphics.cpp152
-rw-r--r--engines/parallaction/graphics.h74
-rw-r--r--engines/parallaction/gui_br.cpp78
-rw-r--r--engines/parallaction/gui_ns.cpp91
-rw-r--r--engines/parallaction/input.cpp188
-rw-r--r--engines/parallaction/input.h45
-rw-r--r--engines/parallaction/objects.cpp83
-rw-r--r--engines/parallaction/objects.h145
-rw-r--r--engines/parallaction/parallaction.cpp485
-rw-r--r--engines/parallaction/parallaction.h490
-rw-r--r--engines/parallaction/parallaction_br.cpp221
-rw-r--r--engines/parallaction/parallaction_ns.cpp122
-rw-r--r--engines/parallaction/parser.cpp223
-rw-r--r--engines/parallaction/parser.h140
-rw-r--r--engines/parallaction/parser_br.cpp142
-rw-r--r--engines/parallaction/parser_ns.cpp61
-rw-r--r--engines/parallaction/saveload.cpp180
-rw-r--r--engines/parallaction/saveload.h96
-rw-r--r--engines/parallaction/staticres.cpp15
-rw-r--r--engines/parallaction/walk.cpp8
-rw-r--r--engines/queen/input.cpp5
-rw-r--r--engines/queen/journal.cpp10
-rw-r--r--engines/queen/logic.cpp10
-rw-r--r--engines/queen/midiadlib.cpp2
-rw-r--r--engines/queen/queen.cpp69
-rw-r--r--engines/queen/queen.h9
-rw-r--r--engines/queen/resource.cpp2
-rw-r--r--engines/queen/sound.cpp65
-rw-r--r--engines/queen/talk.cpp2
-rw-r--r--engines/saga/animation.cpp5
-rw-r--r--engines/saga/detection.cpp51
-rw-r--r--engines/saga/displayinfo.h14
-rw-r--r--engines/saga/input.cpp3
-rw-r--r--engines/saga/interface.cpp85
-rw-r--r--engines/saga/interface.h5
-rw-r--r--engines/saga/introproc_ihnm.cpp10
-rw-r--r--engines/saga/itedata.cpp14
-rw-r--r--engines/saga/itedata.h2
-rw-r--r--engines/saga/music.cpp22
-rw-r--r--engines/saga/music.h3
-rw-r--r--engines/saga/rscfile.cpp157
-rw-r--r--engines/saga/saga.cpp62
-rw-r--r--engines/saga/saga.h9
-rw-r--r--engines/saga/scene.cpp2
-rw-r--r--engines/saga/sfuncs.cpp43
-rw-r--r--engines/saga/sndres.cpp61
-rw-r--r--engines/saga/sndres.h1
-rw-r--r--engines/saga/sound.cpp47
-rw-r--r--engines/saga/sound.h7
-rw-r--r--engines/saga/sprite.cpp12
-rw-r--r--engines/scumm/actor.cpp208
-rw-r--r--engines/scumm/actor.h69
-rw-r--r--engines/scumm/akos.cpp28
-rw-r--r--engines/scumm/boxes.cpp20
-rw-r--r--engines/scumm/charset-fontdata.cpp1
-rw-r--r--engines/scumm/charset.cpp22
-rw-r--r--engines/scumm/charset.h14
-rw-r--r--engines/scumm/detection.cpp104
-rw-r--r--engines/scumm/detection_tables.h3
-rw-r--r--engines/scumm/dialogs.cpp64
-rw-r--r--engines/scumm/dialogs.h6
-rw-r--r--engines/scumm/file.cpp22
-rw-r--r--engines/scumm/file.h39
-rw-r--r--engines/scumm/file_nes.cpp6
-rw-r--r--engines/scumm/file_nes.h8
-rw-r--r--engines/scumm/gfx.cpp70
-rw-r--r--engines/scumm/gfx.h3
-rw-r--r--engines/scumm/gfxARM.s79
-rw-r--r--engines/scumm/he/cup_player_he.cpp6
-rw-r--r--engines/scumm/he/intern_he.h9
-rw-r--r--engines/scumm/he/script_v100he.cpp90
-rw-r--r--engines/scumm/he/script_v60he.cpp5
-rw-r--r--engines/scumm/he/script_v70he.cpp7
-rw-r--r--engines/scumm/he/script_v71he.cpp12
-rw-r--r--engines/scumm/he/script_v72he.cpp24
-rw-r--r--engines/scumm/he/script_v80he.cpp6
-rw-r--r--engines/scumm/he/script_v90he.cpp310
-rw-r--r--engines/scumm/input.cpp10
-rw-r--r--engines/scumm/insane/insane.cpp25
-rw-r--r--engines/scumm/insane/insane.h17
-rw-r--r--engines/scumm/insane/insane_iact.cpp15
-rw-r--r--engines/scumm/module.mk2
-rw-r--r--engines/scumm/object.cpp7
-rw-r--r--engines/scumm/resource.cpp8
-rw-r--r--engines/scumm/resource_v4.cpp2
-rw-r--r--engines/scumm/saveload.cpp125
-rw-r--r--engines/scumm/saveload.h8
-rw-r--r--engines/scumm/script.cpp12
-rw-r--r--engines/scumm/script_v5.cpp4
-rw-r--r--engines/scumm/script_v6.cpp13
-rw-r--r--engines/scumm/script_v8.cpp8
-rw-r--r--engines/scumm/scumm-md5.h26
-rw-r--r--engines/scumm/scumm.cpp90
-rw-r--r--engines/scumm/scumm.h46
-rw-r--r--engines/scumm/smush/channel.h15
-rw-r--r--engines/scumm/smush/chunk.cpp168
-rw-r--r--engines/scumm/smush/imuse_channel.cpp48
-rw-r--r--engines/scumm/smush/saud_channel.cpp24
-rw-r--r--engines/scumm/smush/smush_player.cpp228
-rw-r--r--engines/scumm/smush/smush_player.h35
-rw-r--r--engines/scumm/string.cpp2
-rw-r--r--engines/scumm/thumbnail.cpp130
-rw-r--r--engines/sky/control.cpp25
-rw-r--r--engines/sky/intro.cpp7
-rw-r--r--engines/sky/intro.h1
-rw-r--r--engines/sky/logic.cpp5
-rw-r--r--engines/sky/mouse.cpp1
-rw-r--r--engines/sky/sky.cpp41
-rw-r--r--engines/sky/sky.h1
-rw-r--r--engines/sky/skydefs.h16
-rw-r--r--engines/sky/sound.cpp15
-rw-r--r--engines/sky/sound.h2
-rw-r--r--engines/sword1/animation.cpp5
-rw-r--r--engines/sword1/control.cpp12
-rw-r--r--engines/sword1/control.h1
-rw-r--r--engines/sword1/credits.cpp17
-rw-r--r--engines/sword1/logic.cpp2
-rw-r--r--engines/sword1/music.cpp2
-rw-r--r--engines/sword1/sword1.cpp203
-rw-r--r--engines/sword1/sword1.h2
-rw-r--r--engines/sword2/animation.cpp4
-rw-r--r--engines/sword2/controls.cpp8
-rw-r--r--engines/sword2/function.cpp2
-rw-r--r--engines/sword2/palette.cpp2
-rw-r--r--engines/sword2/resman.cpp4
-rw-r--r--engines/sword2/screen.cpp10
-rw-r--r--engines/sword2/sound.h2
-rw-r--r--engines/sword2/startup.cpp18
-rw-r--r--engines/sword2/sword2.cpp91
-rw-r--r--engines/sword2/sword2.h3
-rw-r--r--engines/tinsel/config.cpp111
-rw-r--r--engines/tinsel/config.h22
-rw-r--r--engines/tinsel/cursor.cpp7
-rw-r--r--engines/tinsel/detection.cpp235
-rw-r--r--engines/tinsel/dw.h7
-rw-r--r--engines/tinsel/inventory.cpp273
-rw-r--r--engines/tinsel/music.cpp8
-rw-r--r--engines/tinsel/music.h2
-rw-r--r--engines/tinsel/saveload.cpp22
-rw-r--r--engines/tinsel/scn.cpp2
-rw-r--r--engines/tinsel/sound.cpp4
-rw-r--r--engines/tinsel/sound.h3
-rw-r--r--engines/tinsel/tinlib.cpp12
-rw-r--r--engines/tinsel/tinsel.cpp49
-rw-r--r--engines/tinsel/tinsel.h18
-rw-r--r--engines/touche/detection.cpp73
-rw-r--r--engines/touche/graphics.cpp5
-rw-r--r--engines/touche/graphics.h2
-rw-r--r--engines/touche/menu.cpp10
-rw-r--r--engines/touche/opcodes.cpp4
-rw-r--r--engines/touche/saveload.cpp7
-rw-r--r--engines/touche/staticres.cpp5
-rw-r--r--engines/touche/touche.cpp59
-rw-r--r--engines/touche/touche.h12
-rw-r--r--graphics/dxa_player.cpp1
-rw-r--r--graphics/dxa_player.h6
-rw-r--r--graphics/font.cpp1
-rw-r--r--graphics/iff.cpp9
-rw-r--r--graphics/imageman.cpp74
-rw-r--r--graphics/imageman.h17
-rw-r--r--graphics/module.mk3
-rw-r--r--graphics/scaler.h16
-rw-r--r--graphics/scaler/hq2x_i386.asm5
-rw-r--r--graphics/scaler/hq3x_i386.asm5
-rw-r--r--graphics/scaler/thumbnail_intern.cpp (renamed from graphics/scaler/thumbnail.cpp)91
-rw-r--r--graphics/surface.cpp5
-rw-r--r--graphics/surface.h19
-rw-r--r--graphics/thumbnail.cpp174
-rw-r--r--graphics/thumbnail.h69
-rw-r--r--gui/ThemeModern.cpp12
-rw-r--r--gui/ThemeModern.h21
-rw-r--r--gui/about.cpp2
-rw-r--r--gui/browser.cpp13
-rw-r--r--gui/browser.h10
-rw-r--r--gui/credits.h31
-rw-r--r--gui/launcher.cpp356
-rw-r--r--gui/launcher.h10
-rw-r--r--gui/massadd.cpp10
-rw-r--r--gui/massadd.h4
-rw-r--r--gui/newgui.cpp10
-rw-r--r--gui/options.cpp10
-rw-r--r--gui/theme-config.cpp33
-rw-r--r--gui/theme.cpp105
-rw-r--r--gui/theme.h6
-rw-r--r--gui/themebrowser.cpp10
-rw-r--r--gui/themebrowser.h2
-rw-r--r--gui/themes/classic080.ini7
-rw-r--r--gui/themes/modern.ini29
-rw-r--r--gui/themes/modern.zipbin42693 -> 54022 bytes
-rw-r--r--gui/widget.cpp3
-rw-r--r--ports.mk2
-rw-r--r--sound/adpcm.cpp2
-rw-r--r--sound/audiocd.cpp1
-rw-r--r--sound/flac.cpp9
-rw-r--r--sound/flac.h1
-rw-r--r--sound/mididrv.cpp11
-rw-r--r--sound/mididrv.h4
-rw-r--r--sound/midiparser.h6
-rw-r--r--sound/midiparser_xmidi.cpp63
-rw-r--r--sound/mixer.cpp1
-rw-r--r--sound/mods/infogrames.cpp25
-rw-r--r--sound/mods/infogrames.h17
-rw-r--r--sound/mp3.cpp2
-rw-r--r--sound/mp3.h1
-rw-r--r--sound/softsynth/mt32.cpp7
-rw-r--r--sound/softsynth/mt32/mt32_file.cpp4
-rw-r--r--sound/softsynth/mt32/mt32_file.h2
-rw-r--r--sound/softsynth/mt32/partial.cpp2
-rw-r--r--sound/softsynth/mt32/synth.cpp2
-rw-r--r--sound/softsynth/mt32/tables.cpp2
-rw-r--r--sound/vorbis.cpp2
-rw-r--r--sound/vorbis.h1
-rw-r--r--sound/wave.cpp4
-rw-r--r--test/common/bufferedreadstream.h11
-rw-r--r--test/common/bufferedseekablereadstream.h23
-rw-r--r--test/common/func.h60
-rw-r--r--test/common/hashmap.h51
-rw-r--r--test/common/queue.h80
-rw-r--r--test/common/seekablesubreadstream.h21
-rw-r--r--test/common/str.h77
-rw-r--r--test/common/stream.h46
-rw-r--r--test/common/subreadstream.h2
-rw-r--r--tools/create_drascula/create_drascula.cpp12
-rw-r--r--tools/create_drascula/create_drascula.h34
-rw-r--r--tools/create_drascula/staticdata.h1626
-rw-r--r--tools/create_kyradat/create_kyradat.cpp23
-rw-r--r--tools/create_kyradat/create_kyradat.h37
-rw-r--r--tools/create_kyradat/hof_cd.h11
-rw-r--r--tools/create_kyradat/hof_demo.h5
-rw-r--r--tools/create_kyradat/hof_floppy.h22
-rw-r--r--tools/create_kyradat/lol_demo.h15
-rw-r--r--tools/create_kyradat/misc.h23
-rw-r--r--tools/create_kyradat/pak.h2
-rwxr-xr-xtools/credits.pl21
-rw-r--r--tools/md5table.c1
-rw-r--r--tools/scumm-md5.txt24
749 files changed, 31476 insertions, 16765 deletions
diff --git a/AUTHORS b/AUTHORS
index d7afb06dc9..d0c015581d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,11 @@ ScummVM Team
Max Horn
Eugene Sandulenko
+ Retired Project Leaders
+ -----------------------
+ Vincent Hamm - ScummVM co-founder, Original Cruise/CinE author
+ Ludvig Strigeus - Original ScummVM and SimonVM author
+
Engine Teams
------------
SCUMM:
@@ -134,7 +139,6 @@ ScummVM Team
Kostas Nakos
PlayStation 2:
- Robert Goeffringmann
Max Lingua
PSP (PlayStation Portable):
@@ -163,9 +167,12 @@ ScummVM Team
Johannes Schickel
Miscellaneous:
- David Corrales-Lopez - Filesystem access improvements
+ David Corrales-Lopez - Filesystem access improvements (GSoC 2007
+ task)
Jerome Fisher - MT-32 emulator
Jochen Hoenicke - Speaker & PCjr sound support, Adlib work
+ Chris Page - Return to launcher, savestate improvements,
+ leak fixes, ... (GSoC 2008 task)
Robin Watts - ARM assembly routines for nice speedups on
several ports; improvements to the sound mixer
@@ -184,13 +191,14 @@ ScummVM Team
Nicolas Bacca - Former WinCE porter
Ralph Brorsen - Help with GUI implementation
Jamieson Christian - iMUSE, MIDI, all things musical
+ Hans-Jorg Frieden - Former AmigaOS 4 packager
+ Robert Goeffringmann - Original PS2 porter
Ruediger Hanke - Port: MorphOS
- Vincent Hamm - ScummVM co-founder, Original Cruise/CinE author
Felix Jakschitsch - Zak256 reverse engineering
Mutwin Kraus - Original MacOS porter
Peter Moraliyski - Port: GP32
+ Juha Niemimaki - Formaer AmigaOS 4 packager
Jeremy Newman - Former webmaster
- Ludvig Strigeus - Original ScummVM and SimonVM author
Lionel Ulmer - Port: X11
Won Star - Former GP32 porter
@@ -199,9 +207,7 @@ Other contributions
Packages
--------
AmigaOS 4:
- Hans-Jorg Frieden
Hubert Maier
- Juha Niemimaki
Atari/FreeMiNT:
Keith Scroggins
@@ -260,6 +266,7 @@ Other contributions
Stuart Caie - Decoders for Simon 1 Amiga data files
Paolo Costabel - PSP port contributions
Thierry Crozat - Support for Broken Sword 1 Macintosh version
+ Martin Doucha - CinE engine objectification
Thomas Fach-Pedersen - ProTracker module player
Benjamin Haisch - Heavily improved de-/encoder for DXA videos
Janne Huttunen - V3 actor mask support, Dig/FT SMUSH audio
@@ -289,15 +296,18 @@ Special thanks to
Sander Buskens - For his work on the initial reversing of Monkey2
Canadacow - For the original MT-32 emulator
Kevin Carnes - For Scumm16, the basis of ScummVM's older gfx codecs
+ Curt Coder - For the original TrollVM (preAGI) code
Patrick Combet - For the original Gobliiins ADL player
Ivan Dubrov - For contributing the initial version of the Gobliiins
engine
+ Till Kresslein - For design of modern ScummVM GUI
Jezar - For his freeverb filter implementation
Jim Leiterman - Various info on his FM-TOWNS/Marty SCUMM ports
lloyd - For deep tech details about C64 Zak & MM
Sarien Team - Original AGI engine code
Jimmi Thogersen - For ScummRev, and much obscure code/documentation
Tristan - For additional work on the original MT-32 emulator
+ James Woodcock - Soundtrack enhancements
Tony Warriner and everyone at Revolution Software Ltd. for sharing with us
the source of some of their brilliant games, allowing us to release
diff --git a/COPYRIGHT b/COPYRIGHT
index c4c3cf0a65..b37c1c0fe5 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -60,6 +60,7 @@ Eugene Sandulenko
Johannes Schickel
Won Star
Ludvig Strigeus
+Keith Scroggins
David Symonds
Jordi Vilalta
Robin Watts
@@ -74,23 +75,34 @@ Patches contributed by:
Laura Abbott "sageofminerva"
Vikram Aggarwal "youngelf"
+the rara avis "theraraavis"
Dieter Baron "dillo"
Alban Bedel "albeu"
Bodo Bellut "bellut"
+Bramvandijk "bramvandijk"
Andreas Bierfert "awjb"
Elio Blanca "eblanca76"
+Bastien Bouclet "bgk"
David Breakey "dbreakey"
Robert Buchholz "prendi"
-Rainer Canavan
+Rainer Canavan "canavan"
Mathieu Carot "yokna"
Stefano Ceccherini "jackburton"
Travis S Coady "theealien"
Josh Coalson "jcoalson"
Thomas Combeleran "hibernatus"
+Kees Cook "keescook"
Carlos Corbacho "cathectic"
Roberto Costa "fiix76"
+Thiery Crozat "criezy"
+dc france "erwan2004"
+dewt "mncl"
+Martin Doucha "next_ghost"
Michael Drueing "doc_wagon"
+dubsdj
Matthew Duggan "stauff1"
+Olivier Duverne "richiefs"
+Andrei Dziahel "develop7"
John Eckerdal "johneck"
Thomas Fach-Pedersen "madm00se"
Florent "flobo"
@@ -109,6 +121,7 @@ Stefan Haubenthal "polluks"
Alexander Holler "holler"
Falk Hueffner "mellum"
Casey Hutchinson "nnooiissee"
+j0tt
Gregor Jasny "gjasny"
Jellby "jellby"
Joerg "macdrega"
@@ -122,38 +135,49 @@ Janne Kujanpaa "jukuja"
Jay Lanagan "r0ni"
Norbert Lange "nolange"
Manuel Lauss "mlau2"
+Rolf Leggewie "leggewie"
Duncan Lock "dflock"
Mark Lodato "itsr0y"
Fridvin Logi "phillip_j_fry"
+Lostech "lostech"
Georg Lukas "ge0rg"
Dmitry Marakasov "amdmi3"
-Markus "meist3r"
Connor McLeod "mcleod2032"
Mickey McMurray "metafox"
Vladimir Menshakov "megath"
+Adam Metcalf "gamblore"
Frank Meyering "frank_m24"
Gael Le Migno "kilobug"
Alyssa Anne Milburn "fuzzie"
Andy Molloy "maloi"
+Sean Murrau "lightcast"
Armin Mueller "arm_in"
Andrea Musuruane "musuruan"
KO Myung-Hun "lvzuufx"
+Markus Napp "meist3r"
Peter Naulls "pnaulls"
Christian Neumair "mannythegnome"
Nicos "anarxia"
Juha Niemimaki "capehill"
Markus Niemisto "niemisto"
+ole
Chris Paras "paras_rasmatazz"
Aubin Paul "outlyer"
+Vincent Pelletier "subdino"
+phi1
+Pix2 "pix2"
Carsten Pohl "carstenpohl"
Markus Pyykko "mankeli"
Richard "trinity78"
Felix Riemann "kirschsaft"
+Thomas Richter "thorfdbg"
Timo Roehling "t1m0"
Andreas Roever "roever"
Jonathan Rogers "jonner"
Marek Roth "logicdeluxe"
+Uwe Ryssel "uweryssel"
Simon Sawatzki "simsaw"
+Scarlatti "escarlate"
Daniel Schepler "dschepler"
Florian Schmitt "fatpenguin"
Mark Schreiber "mark7"
@@ -161,12 +185,17 @@ Ben Shadwick "benshadwick"
Jean-Yves Simon "lethalwp"
Andrej Sinicyn "andrej4000"
Andre Souza "luke_br"
+spookypeanut "spookypeanut"
Steve Stavropoulos "isnothere"
Daniel Steinberger "amorphousshape"
Sven Strothoff "dataslayer"
Andrea Suatoni "mrhandler"
+tbcarey
+Tim "tipabu"
+Tobigun "tobigun"
Luigi Toscano "ltosky"
Xavier Trochu "xtrochu"
+Michal Tulacek "tutchek"
Michael Udaltsov "cccp99"
Kristof Vansant "lupusbe"
Tim Walters "realmz"
@@ -174,16 +203,6 @@ David Weinehall "weine"
Eric A. Welsh "eweish42"
Yudhi Widyatama "yudhi97"
Robert Wohlrab "moshroum"
+Xanathar "xanathar"
+Grant Yeager "glo_kidd"
Benjamin W. Zale "junior_aepi"
-the rara avis "theraraavis"
-dewt "mncl"
-dubsdj
-exo "exofreeze"
-dc france "erwan2004"
-j0tt
-glo kidd "glo_kidd"
-ole
-phi1
-spookypeanut "spookypeanut"
-tbcarey
-Tim "tipabu"
diff --git a/NEWS b/NEWS
index 086b1dcb99..113ee4670a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,10 +2,22 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
http://scummvm.sourceforge.net/daily/ChangeLog
0.13.0 (????-??-??)
+ General:
+ - Added MIDI driver for Atari ST / FreeMint.
+ - Added a 'Load' button to the Launcher (not supported by all engines).
+ - Added a new global main menu (GMM) dialog usable from all engines.
+ - Added the ability to return to the launcher from running games (via the GMM).
+
New Games:
- Added support for Discworld.
-0.12.0 (????-??-??)
+ KYRA:
+ - Added support for Auto-save feature.
+
+ SCUMM:
+ - Fixed a long-time bug which caused talkspeed and talkdelay to be mixed up.
+
+0.12.0 (2008-08-31)
New Games:
- Added support for The Legend of Kyrandia: Book Two: Hand of Fate.
- Added support for The Legend of Kyrandia: Book Three: Malcolm's Revenge.
@@ -30,6 +42,10 @@ For a more comprehensive changelog for the latest experimental SVN code, see:
Simon the Sorcerer 1.
- Fixed palette issues in Amiga versions of Simon the Sorcerer 1.
+ Queen:
+ - Speech is played at the correct sample rate. (It used to be pitched a bit
+ too low.)
+
SCUMM:
- Rewrote parts of Digital iMUSE, fixing some bugs.
- Rewrote the internal timer code, fixing some speed issues in e.g. COMI.
diff --git a/README b/README
index ac44f53cab..cd19d97bbd 100644
--- a/README
+++ b/README
@@ -39,10 +39,12 @@ Table of Contents:
* 5.1 Command Line Options
* 5.2 Language Options
* 5.3 Graphics Filters
- * 5.4 Hotkeys
+ * 5.4 Global Menu
+ * 5.5 Hotkeys
6.0) Savegames
* 6.1 Autosaves
* 6.2 Converting savegames
+ * 6.3 Viewing/Loading savegames from the command line
7.0) Music and Sound
* 7.1 Adlib emulation
* 7.2 FluidSynth MIDI emulation
@@ -182,17 +184,23 @@ GOB Games by Coktel Vision:
Gobliiins [gob1]
Gobliins 2 [gob2]
Goblins 3 [gob3]
+ Lost in Time [lostintime]
+ The Bizarre Adventures of Woodruff
+ and the Schnibble [woodruff]
Ween: The Prophecy [ween]
Other Games:
Beneath a Steel Sky [sky]
Broken Sword 1: The Shadow of the Templars [sword1]
Broken Sword 2: The Smoking Mirror [sword2]
+ Drascula: The Vampire Strikes Back [drascula]
Flight of the Amazon Queen [queen]
Future Wars [fw]
Inherit the Earth: Quest for the Orb [ite]
Nippon Safes Inc. [nippon]
The Legend of Kyrandia [kyra1]
+ The Legend of Kyrandia: The Hand of Fate [kyra2]
+ The Legend of Kyrandia: Malcolm's Revenge [kyra3]
Touche: The Adventures of the Fifth
Musketeer [touche]
@@ -781,6 +789,7 @@ arguments -- see the next section.
-h, --help Display a brief help text and exit
-z, --list-games Display list of supported games and exit
-t, --list-targets Display list of configured targets and exit
+ --list-saves=TARGET Display a list of savegames for the game (TARGET) specified
-c, --config=CONFIG Use alternate configuration file
-p, --path=PATH Path to where the game is installed
@@ -968,7 +977,38 @@ Likewise, games that originally were using 640x480 (such as COMI or Broken Sword
will be scaled to 1280x960 and 1920x1440.
-5.4) Hot Keys:
+5.4) Global Menu:
+---- ------------
+
+The Global Menu is a general menu which is available to all of the game engines
+by pressing F6. From this menu there are the following buttons: Resume,
+Options, About, Return to Launcher, and Quit. Selecting 'Options' will display
+a dialog where basic audio settings, such as volume levels, can be adjusted.
+Selecting 'Return to Launcher' will close the current game and return the user
+back to the ScummVM Launcher, where another game may be selected to play.
+
+Note: Returning to the Launcher is not supported by all of the engines,
+ and the button will be disabled in the Global Menu if it is not supported.
+
+Engines which currently support Returning to the Launcher are:
+
+ AGI
+ AGOS
+ CINE
+ GOB
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+
+5.5) Hot Keys:
---- ---------
TODO
TODO: Rework this section to clearly state which hotkeys are implemented in *all*
@@ -982,6 +1022,7 @@ ScummVM supports various in-game hotkeys. They differ between SCUMM games and
other games.
Common:
+ F6 - Displays the Global Menu
Cmd-q - Quit (Mac OS X)
Ctrl-q - Quit (other unices including Linux)
Ctrl-z OR Alt-x - Quit (other platforms)
@@ -1138,45 +1179,93 @@ The platforms that currently have a different default directory are:
6.1) Autosaves:
---- ----------
-For some games (namely "Beneath a Steel Sky", "Flight of the Amazon
-Queen" and all SCUMM games), ScummVM will by default automatically
-save the current state every five minutes (adjustable via the
-"autosave_period" config setting). For the SCUMM engine, it will save
-in Slot 0. This savestate can then be loaded again via Ctrl-0, or the
-F5 menu.
+For some games, (namely "Beneath a Steel Sky", "Flight of the Amazon Queen",
+all AGI games, and all SCUMM games), ScummVM will by default automatically
+save the current state every five minutes (adjustable via the "autosave_period"
+config setting). For the AGI and SCUMM engines, it will save in Slot 0. For the
+SCUMM engine, this savestate can then be loaded again via Ctrl-0, or the F5
+menu.
6.2) Converting Savegames:
----- ----------
-Using savegames from original versions, isn't supported by all game engines. Only
-the following games, can use savedgames from their original versions.
+---- ---------------------
+Using savegames from original versions, isn't supported by all game engines.
+Only the following games, can use savegames from their original versions.
Elvira 1
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'elvira1.xxx'
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'elvira1.xxx'
Elvira 2
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'elvira2-pc.xxx' (DOS version) or
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'elvira2-pc.xxx' (DOS version) or
'elvira2.xxx' (Other versions)
Waxworks
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'waxworks-pc.xxx' (DOS version) or
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'waxworks-pc.xxx' (DOS version) or
'waxworks.xxx' (Other versions)
Simon the Sorcerer 1
- - Rename the savedgame to 'simon1.xxx'
+ - Rename the savegame to 'simon1.xxx'
Simon the Sorcerer 1
- - Rename the savedgame to 'simon2.xxx'
+ - Rename the savegame to 'simon2.xxx'
The Feeble Files
- - Rename the savedgame to 'feeble.xxx'
+ - Rename the savegame to 'feeble.xxx'
Where 'xxx' is exact the saved game slot (ie 001) under ScummVM
+6.3) Viewing/Loading savegames from the command line:
+---- ------------------------------------------------
+
+--list-saves:
+
+ This switch may be used to display a list of the current savegames
+ of the specified target game and their corresponding save slots.
+
+ Usage: --list-saves=[TARGET], where [TARGET] is the target game.
+
+ Engines which currently support --list-saves are:
+
+ AGI
+ AGOS
+ CINE
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+--save-slot/-x:
+
+ This switch may be used to load a savegame directly from the command line.
+
+ Usage: --save-slot[SLOT] or -x[SLOT], where [SLOT] is the save slot number.
+
+ Engines which currently support --save-slot/-x are:
+
+ AGI
+ CINE
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+
7.0) Music and Sound:
---- ----------------
@@ -1322,34 +1411,39 @@ sequencer support does not work, you can always fall back on Adlib emulation.
7.6.1) Playing sound with ALSA sequencer: [UNIX ONLY]
------ ----------------------------------
-If you have installed the ALSA driver with the sequencer support, then
-set the environment variable SCUMMVM_PORT or the config file parameter
-alsa_port to your sequencer port. The default is "65:0".
+If you have installed the ALSA driver with the sequencer support, then set the
+environment variable SCUMMVM_PORT or the config file parameter alsa_port to
+your sequencer port. The default is to try both "65:0" and "17:0".
Here is a little howto on how to use the ALSA sequencer with your soundcard.
In all cases, to have a list of all the sequencer ports you have, try the
command "aconnect -o -l". This should give output similar to:
-client 64: 'External MIDI 0' [type=kernel]
- 0 'MIDI 0-0 '
-client 65: 'Emu10k1 WaveTable' [type=kernel]
+
+client 14: 'Midi Through' [type=kernel]
+ 0 'Midi Through Port-0'
+client 16: 'SBLive! Value [CT4832]' [type=kernel]
+ 0 'EMU10K1 MPU-401 (UART)'
+client 17: 'Emu10k1 WaveTable' [type=kernel]
0 'Emu10k1 Port 0 '
1 'Emu10k1 Port 1 '
2 'Emu10k1 Port 2 '
3 'Emu10k1 Port 3 '
-client 128: 'Client-128' [type=user]
+client 128: 'TiMidity' [type=user]
0 'TiMidity port 0 '
1 'TiMidity port 1 '
+ 2 'TiMidity port 2 '
+ 3 'TiMidity port 3 '
-This means the external MIDI output of the sound card is located on the
-port 64:0, four WaveTable MIDI outputs in 65:0, 65:1, 65:2
-and 65:3, and two TiMidity ports, located at 128:0 and 128:1.
+The most important bit here is that there are four WaveTable MIDI outputs
+located at 17:0, 17:1, 17:2 and 17:3, and four TiMidity ports located at 128:0,
+128:1, 128:2 and 128:3.
If you have a FM-chip on your card, like the SB16, then you have to load
the SoundFonts using the sbiload software. Example:
- sbiload -p 65:0 /etc/std.o3 /etc/drums.o3
+ sbiload -p 17:0 /etc/std.o3 /etc/drums.o3
If you have a WaveTable capable sound card, you have to load a sbk or sf2
-SoundFont using the sfxload software. Example:
+SoundFont using the sfxload or asfxload software. Example:
sfxload /path/to/8mbgmsfx.sf2
If you don't have a MIDI capable soundcard, there are two options: FluidSynth
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp
index afa71e1fd1..a2616bc58a 100644
--- a/backends/events/default/default-events.cpp
+++ b/backends/events/default/default-events.cpp
@@ -96,7 +96,8 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) :
_boss(boss),
_buttonState(0),
_modifierState(0),
- _shouldQuit(false) {
+ _shouldQuit(false),
+ _shouldRTL(false) {
assert(_boss);
@@ -211,6 +212,9 @@ DefaultEventManager::~DefaultEventManager() {
_boss->unlockMutex(_timeMutex);
_boss->unlockMutex(_recorderMutex);
+ if (!artificialEventQueue.empty())
+ artificialEventQueue.clear();
+
if (_playbackFile != NULL) {
delete _playbackFile;
}
@@ -372,10 +376,8 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
if (!_artificialEventQueue.empty()) {
event = _artificialEventQueue.pop();
result = true;
- }
-
- // poll for event from backend
- if (!result) {
+ } else {
+ // poll for event from backend
result = _boss->pollEvent(event);
if (result) {
// send key press events to keymapper
@@ -415,7 +417,6 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
_modifierState = event.kbd.flags;
-
// init continuous event stream
// not done on PalmOS because keyboard is emulated and keyup is not generated
#if !defined(PALMOS_MODE)
@@ -424,8 +425,39 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_currentKeyDown.flags = event.kbd.flags;
_keyRepeatTime = time + kKeyRepeatInitialDelay;
#endif
-
- if (event.kbd.keycode == Common::KEYCODE_F6 && event.kbd.flags == 0) {
+ // Global Main Menu
+ // FIXME: F6 is not the best trigger, it conflicts with some games!!!
+ if (event.kbd.keycode == Common::KEYCODE_F6) {
+ if (g_engine && !g_engine->isPaused()) {
+ Common::Event menuEvent;
+ menuEvent.type = Common::EVENT_MAINMENU;
+
+ // FIXME: GSoC RTL branch passes the F6 key event to the
+ // engine, and also enqueues a EVENT_MAINMENU. For now,
+ // we just drop the key event and return an EVENT_MAINMENU
+ // instead. This way, we don't have to add special cases
+ // to engines (like it was the case for LURE in the RTL branch).
+ //
+ // However, this has other consequences, possibly negative ones.
+ // Like, what happens with key repeat for the trigger key?
+
+ //pushEvent(menuEvent);
+ event = menuEvent;
+
+ // FIXME: Since now we do not push another MAINMENU event onto
+ // our event stack, the GMM would never open, so we have to do
+ // that here. Of course when the engine would handle MAINMENU
+ // as an event now and open up the GMM itself it would open the
+ // menu twice.
+ if (g_engine && !g_engine->isPaused())
+ g_engine->mainMenuDialog();
+
+ if (_shouldQuit)
+ event.type = Common::EVENT_QUIT;
+ else if (_shouldRTL)
+ event.type = Common::EVENT_RTL;
+ }
+ } else if (event.kbd.keycode == Common::KEYCODE_F7 && event.kbd.flags == 0) {
if (_vk->isDisplaying()) {
_vk->close(true);
} else {
@@ -435,7 +467,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
if (!isPaused) g_engine->pauseEngine(false);
result = false;
}
- } else if (event.kbd.keycode == Common::KEYCODE_F7 && event.kbd.flags == 0) {
+ } else if (event.kbd.keycode == Common::KEYCODE_F8 && event.kbd.flags == 0) {
if (!_remap) {
_remap = true;
Common::RemapDialog _remapDialog;
@@ -446,8 +478,8 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_remap = false;
}
}
-
break;
+
case Common::EVENT_KEYUP:
_modifierState = event.kbd.flags;
if (event.kbd.keycode == _currentKeyDown.keycode) {
@@ -464,6 +496,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= LBUTTON;
break;
+
case Common::EVENT_LBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~LBUTTON;
@@ -473,11 +506,26 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= RBUTTON;
break;
+
case Common::EVENT_RBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~RBUTTON;
break;
+ case Common::EVENT_MAINMENU:
+ if (g_engine && !g_engine->isPaused())
+ g_engine->mainMenuDialog();
+
+ if (_shouldQuit)
+ event.type = Common::EVENT_QUIT;
+ else if (_shouldRTL)
+ event.type = Common::EVENT_RTL;
+ break;
+
+ case Common::EVENT_RTL:
+ _shouldRTL = true;
+ break;
+
case Common::EVENT_QUIT:
if (ConfMan.getBool("confirm_exit")) {
if (g_engine)
@@ -488,6 +536,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
g_engine->pauseEngine(false);
} else
_shouldQuit = true;
+
break;
default:
@@ -511,7 +560,13 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
}
void DefaultEventManager::pushEvent(const Common::Event &event) {
- _artificialEventQueue.push(event);
+
+ // If already received an EVENT_QUIT, don't add another one
+ if (event.type == Common::EVENT_QUIT) {
+ if (!_shouldQuit)
+ artificialEventQueue.push(event);
+ } else
+ artificialEventQueue.push(event);
}
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)
diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h
index 0087265e2a..7bd316475a 100644
--- a/backends/events/default/default-events.h
+++ b/backends/events/default/default-events.h
@@ -60,6 +60,7 @@ class DefaultEventManager : public Common::EventManager {
int _buttonState;
int _modifierState;
bool _shouldQuit;
+ bool _shouldRTL;
class RandomSourceRecord {
public:
@@ -128,6 +129,9 @@ public:
virtual int getButtonState() const { return _buttonState; }
virtual int getModifierState() const { return _modifierState; }
virtual int shouldQuit() const { return _shouldQuit; }
+ virtual int shouldRTL() const { return _shouldRTL; }
+ virtual void resetRTL() { _shouldRTL = false; }
+
virtual Common::Keymapper *getKeymapper() { return _keymapper; }
};
diff --git a/backends/fs/abstract-fs.cpp b/backends/fs/abstract-fs.cpp
new file mode 100644
index 0000000000..6daad7152a
--- /dev/null
+++ b/backends/fs/abstract-fs.cpp
@@ -0,0 +1,40 @@
+/* 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 "backends/fs/abstract-fs.h"
+
+const char *AbstractFilesystemNode::lastPathComponent(const Common::String &str, const char sep) {
+ // TODO: Get rid of this eventually! Use Common::lastPathComponent instead
+ if(str.empty())
+ return "";
+
+ const char *start = str.c_str();
+ const char *cur = start + str.size() - 2;
+
+ while (cur >= start && *cur != sep) {
+ --cur;
+ }
+
+ return cur + 1;
+}
diff --git a/backends/fs/abstract-fs.h b/backends/fs/abstract-fs.h
index 8125ad7d95..b3a652f2ae 100644
--- a/backends/fs/abstract-fs.h
+++ b/backends/fs/abstract-fs.h
@@ -43,28 +43,27 @@ typedef Common::Array<AbstractFilesystemNode *> AbstractFSList;
*/
class AbstractFilesystemNode {
protected:
- friend class FilesystemNode;
- typedef Common::String String;
- typedef FilesystemNode::ListMode ListMode;
+ friend class Common::FilesystemNode;
+ typedef Common::FilesystemNode::ListMode ListMode;
/**
- * Returns the child node with the given name. If no child with this name
- * exists, returns 0. When called on a non-directory node, it should
- * handle this gracefully by returning 0.
+ * Returns the child node with the given name. When called on a non-directory
+ * node, it should handle this gracefully by returning 0.
+ * When called with a name not matching any of the files/dirs contained in this
+ * directory, a valid node shold be returned, which returns 'false' upon calling
+ * the exists() method. The idea is that this node can then still can be used to
+ * create a new file via the openForWriting() method.
*
* Example:
* Calling getChild() for a node with path "/foo/bar" using name="file.txt",
* would produce a new node with "/foo/bar/file.txt" as path.
*
- * @note This function will append a separator char (\ or /) to the end of the
- * path if needed.
- *
* @note Handling calls on non-dir nodes gracefully makes it possible to
* switch to a lazy type detection scheme in the future.
*
* @param name String containing the name of the child to create a new node.
*/
- virtual AbstractFilesystemNode *getChild(const String &name) const = 0;
+ virtual AbstractFilesystemNode *getChild(const Common::String &name) const = 0;
/**
* The parent node of this directory.
@@ -72,6 +71,19 @@ protected:
*/
virtual AbstractFilesystemNode *getParent() const = 0;
+ /**
+ * Returns the last component of a given path.
+ *
+ * Examples:
+ * /foo/bar.txt would return /bar.txt
+ * /foo/bar/ would return /bar/
+ *
+ * @param str String containing the path.
+ * @param sep character used to separate path components
+ * @return Pointer to the first char of the last component inside str.
+ */
+ static const char *lastPathComponent(const Common::String &str, const char sep);
+
public:
/**
* Destructor.
@@ -100,7 +112,7 @@ public:
*
* @note By default, this method returns the value of getName().
*/
- virtual String getDisplayName() const { return getName(); }
+ virtual Common::String getDisplayName() const { return getName(); }
/**
* Returns the last component of the path pointed by this FilesystemNode.
@@ -111,12 +123,12 @@ public:
*
* @note This method is very architecture dependent, please check the concrete implementation for more information.
*/
- virtual String getName() const = 0;
+ virtual Common::String getName() const = 0;
/**
* Returns the 'path' of the current node, usable in fopen().
*/
- virtual String getPath() const = 0;
+ virtual Common::String getPath() const = 0;
/**
* Indicates whether this path refers to a directory or not.
@@ -149,9 +161,26 @@ public:
*/
virtual bool isWritable() const = 0;
- /* TODO:
- bool isFile();
- */
+
+ /**
+ * Creates a SeekableReadStream instance corresponding to the file
+ * referred by this node. This assumes that the node actually refers
+ * to a readable file. If this is not the case, 0 is returned.
+ *
+ * @return pointer to the stream object, 0 in case of a failure
+ */
+ virtual Common::SeekableReadStream *openForReading() = 0;
+
+ /**
+ * Creates a WriteStream instance corresponding to the file
+ * referred by this node. This assumes that the node actually refers
+ * to a readable file. If this is not the case, 0 is returned.
+ *
+ * @return pointer to the stream object, 0 in case of a failure
+ */
+ virtual Common::WriteStream *openForWriting() = 0;
};
+
+
#endif //BACKENDS_ABSTRACT_FS_H
diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.cpp b/backends/fs/amigaos4/amigaos4-fs-factory.cpp
index af843b7c78..2b0b2f1908 100644
--- a/backends/fs/amigaos4/amigaos4-fs-factory.cpp
+++ b/backends/fs/amigaos4/amigaos4-fs-factory.cpp
@@ -26,8 +26,6 @@
#include "backends/fs/amigaos4/amigaos4-fs-factory.h"
#include "backends/fs/amigaos4/amigaos4-fs.cpp"
-DECLARE_SINGLETON(AmigaOSFilesystemFactory);
-
AbstractFilesystemNode *AmigaOSFilesystemFactory::makeRootFileNode() const {
return new AmigaOSFilesystemNode();
}
@@ -36,7 +34,7 @@ AbstractFilesystemNode *AmigaOSFilesystemFactory::makeCurrentDirectoryFileNode()
return new AmigaOSFilesystemNode();
}
-AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *AmigaOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new AmigaOSFilesystemNode(path);
}
#endif
diff --git a/backends/fs/amigaos4/amigaos4-fs-factory.h b/backends/fs/amigaos4/amigaos4-fs-factory.h
index 58a7dcd372..03af6e95b9 100644
--- a/backends/fs/amigaos4/amigaos4-fs-factory.h
+++ b/backends/fs/amigaos4/amigaos4-fs-factory.h
@@ -25,7 +25,6 @@
#ifndef AMIGAOS_FILESYSTEM_FACTORY_H
#define AMIGAOS_FILESYSTEM_FACTORY_H
-#include "common/singleton.h"
#include "backends/fs/fs-factory.h"
/**
@@ -33,19 +32,11 @@
*
* Parts of this class are documented in the base interface class, FilesystemFactory.
*/
-class AmigaOSFilesystemFactory : public FilesystemFactory, public Common::Singleton<AmigaOSFilesystemFactory> {
+class AmigaOSFilesystemFactory : public FilesystemFactory {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
-
-protected:
- AmigaOSFilesystemFactory() {};
-
-private:
- friend class Common::Singleton<SingletonBaseType>;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
};
#endif /*AMIGAOS_FILESYSTEM_FACTORY_H*/
diff --git a/backends/fs/amigaos4/amigaos4-fs.cpp b/backends/fs/amigaos4/amigaos4-fs.cpp
index 5bf57ddf34..d517121dc0 100644
--- a/backends/fs/amigaos4/amigaos4-fs.cpp
+++ b/backends/fs/amigaos4/amigaos4-fs.cpp
@@ -36,8 +36,8 @@
#endif
#include "common/util.h"
-#include "engines/engine.h"
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#define ENTER() /* debug(6, "Enter") */
#define LEAVE() /* debug(6, "Leave") */
@@ -52,8 +52,8 @@ const uint32 kExAllBufferSize = 40960; // TODO: is this okay for sure?
class AmigaOSFilesystemNode : public AbstractFilesystemNode {
protected:
BPTR _pFileLock;
- String _sDisplayName;
- String _sPath;
+ Common::String _sDisplayName;
+ Common::String _sPath;
bool _bIsDirectory;
bool _bIsValid;
@@ -74,9 +74,9 @@ public:
/**
* Creates a AmigaOSFilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
*/
- AmigaOSFilesystemNode(const String &p);
+ AmigaOSFilesystemNode(const Common::String &p);
/**
* FIXME: document this constructor.
@@ -96,17 +96,20 @@ public:
virtual ~AmigaOSFilesystemNode();
virtual bool exists() const;
- virtual String getDisplayName() const { return _sDisplayName; };
- virtual String getName() const { return _sDisplayName; };
- virtual String getPath() const { return _sPath; };
+ virtual Common::String getDisplayName() const { return _sDisplayName; };
+ virtual Common::String getName() const { return _sDisplayName; };
+ virtual Common::String getPath() const { return _sPath; };
virtual bool isDirectory() const { return _bIsDirectory; };
virtual bool isReadable() const;
virtual bool isWritable() const;
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
/**
* Creates a list with all the volumes present in the root node.
*/
@@ -116,7 +119,7 @@ public:
/**
* Returns the last component of a given path.
*
- * @param str String containing the path.
+ * @param str Common::String containing the path.
* @return Pointer to the first char of the last component inside str.
*/
const char *lastPathComponent(const Common::String &str) {
@@ -148,10 +151,10 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode() {
LEAVE();
}
-AmigaOSFilesystemNode::AmigaOSFilesystemNode(const String &p) {
+AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
ENTER();
- int len = 0, offset = p.size();
+ int offset = p.size();
//assert(offset > 0);
@@ -161,7 +164,7 @@ AmigaOSFilesystemNode::AmigaOSFilesystemNode(const String &p) {
}
_sPath = p;
- _sDisplayName = lastPathComponent(_sPath);
+ _sDisplayName = ::lastPathComponent(_sPath);
_pFileLock = 0;
_bIsDirectory = false;
@@ -299,14 +302,14 @@ bool AmigaOSFilesystemNode::exists() const {
return nodeExists;
}
-AbstractFilesystemNode *AmigaOSFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *AmigaOSFilesystemNode::getChild(const Common::String &n) const {
ENTER();
if (!_bIsDirectory) {
debug(6, "Not a directory");
return 0;
}
- String newPath(_sPath);
+ Common::String newPath(_sPath);
if (_sPath.lastChar() != '/')
newPath += '/';
@@ -368,10 +371,10 @@ bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
struct ExAllData *ead = data;
do {
- if ((mode == FilesystemNode::kListAll) ||
- (EAD_IS_DRAWER(ead) && (mode == FilesystemNode::kListDirectoriesOnly)) ||
- (EAD_IS_FILE(ead) && (mode == FilesystemNode::kListFilesOnly))) {
- String full_path = _sPath;
+ if ((mode == Common::FilesystemNode::kListAll) ||
+ (EAD_IS_DRAWER(ead) && (mode == Common::FilesystemNode::kListDirectoriesOnly)) ||
+ (EAD_IS_FILE(ead) && (mode == Common::FilesystemNode::kListFilesOnly))) {
+ Common::String full_path = _sPath;
full_path += (char*)ead->ed_Name;
BPTR lock = IDOS->Lock((STRPTR)full_path.c_str(), SHARED_LOCK);
@@ -566,4 +569,12 @@ AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
return myList;
}
+Common::SeekableReadStream *AmigaOSFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *AmigaOSFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
+
#endif //defined(__amigaos4__)
diff --git a/backends/fs/ds/ds-fs-factory.cpp b/backends/fs/ds/ds-fs-factory.cpp
index 2eae2f2403..5c8c3f45f8 100644
--- a/backends/fs/ds/ds-fs-factory.cpp
+++ b/backends/fs/ds/ds-fs-factory.cpp
@@ -45,7 +45,7 @@ AbstractFilesystemNode *DSFilesystemFactory::makeCurrentDirectoryFileNode() cons
}
}
-AbstractFilesystemNode *DSFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *DSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
if (DS::isGBAMPAvailable()) {
return new DS::GBAMPFileSystemNode(path);
} else {
diff --git a/backends/fs/ds/ds-fs-factory.h b/backends/fs/ds/ds-fs-factory.h
index bff21a309d..67e0076b78 100644
--- a/backends/fs/ds/ds-fs-factory.h
+++ b/backends/fs/ds/ds-fs-factory.h
@@ -35,11 +35,9 @@
*/
class DSFilesystemFactory : public FilesystemFactory, public Common::Singleton<DSFilesystemFactory> {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
protected:
DSFilesystemFactory() {};
diff --git a/backends/fs/ds/ds-fs.cpp b/backends/fs/ds/ds-fs.cpp
index cffe4c118d..911702316d 100644
--- a/backends/fs/ds/ds-fs.cpp
+++ b/backends/fs/ds/ds-fs.cpp
@@ -24,6 +24,7 @@
#include "common/util.h"
//#include <NDS/ARM9/console.h> //basic print funcionality
#include "backends/fs/ds/ds-fs.h"
+#include "backends/fs/stdiostream.h"
#include "dsmain.h"
#include "fat/gba_nds_fat.h"
@@ -55,7 +56,7 @@ DSFileSystemNode::DSFileSystemNode() {
}
}
-DSFileSystemNode::DSFileSystemNode(const String& path) {
+DSFileSystemNode::DSFileSystemNode(const Common::String& path) {
// consolePrintf("--%s ",path.c_str());
char disp[128];
@@ -70,7 +71,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path) {
strcpy(disp, pathStr + lastSlash + 1);
- _displayName = String(disp);
+ _displayName = Common::String(disp);
_path = path;
// _isValid = true;
// _isDirectory = false;
@@ -98,7 +99,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path) {
// consolePrintf("%s - Found: %d, Dir: %d\n", pathStr, _isValid, _isDirectory);
}
-DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) {
+DSFileSystemNode::DSFileSystemNode(const Common::String& path, bool isDir) {
// consolePrintf("--%s ",path.c_str());
char disp[128];
@@ -112,7 +113,7 @@ DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) {
strcpy(disp, pathStr + lastSlash + 1);
- _displayName = String(disp);
+ _displayName = Common::String(disp);
_path = path;
_isValid = true;
_isDirectory = isDir;
@@ -167,10 +168,10 @@ bool DSFileSystemNode::getChildren(AbstractFSList &dirList, ListMode mode, bool
_zipFile->getFileName(n);
// consolePrintf("file: %s\n", n);
- if ( (_zipFile->isDirectory() && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)) )
- || (!_zipFile->isDirectory() && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll)) ) )
+ if ( (_zipFile->isDirectory() && ((mode == Common::FilesystemNode::kListDirectoriesOnly) || (mode == Common::FilesystemNode::kListAll)) )
+ || (!_zipFile->isDirectory() && ((mode == Common::FilesystemNode::kListFilesOnly) || (mode == Common::FilesystemNode::kListAll)) ) )
{
- DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + String(n), _zipFile->isDirectory());
+ DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + Common::String(n), _zipFile->isDirectory());
dsfsn->_isDirectory = _zipFile->isDirectory();
dirList.push_back((dsfsn));
}
@@ -195,7 +196,7 @@ AbstractFilesystemNode* DSFileSystemNode::getParent() const {
}
}
- p = new DSFileSystemNode(String(path, lastSlash));
+ p = new DSFileSystemNode(Common::String(path, lastSlash));
((DSFileSystemNode *) (p))->_isDirectory = true;
} else {
p = new DSFileSystemNode();
@@ -204,6 +205,14 @@ AbstractFilesystemNode* DSFileSystemNode::getParent() const {
return p;
}
+Common::SeekableReadStream *DSFileSystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *DSFileSystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
+
//////////////////////////////////////////////////////////////////////////
// GBAMPFileSystemNode - File system using GBA Movie Player and CF card //
//////////////////////////////////////////////////////////////////////////
@@ -216,7 +225,7 @@ GBAMPFileSystemNode::GBAMPFileSystemNode() {
_path = "mp:/";
}
-GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) {
+GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path) {
// consolePrintf("'%s'",path.c_str());
char disp[128];
@@ -245,13 +254,13 @@ GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) {
}
// consolePrintf("Path: %s (%d)\n", check, success);
- _displayName = String(disp);
+ _displayName = Common::String(disp);
_path = path;
_isValid = success == FT_FILE;
_isDirectory = success == FT_DIR;
}
-GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) {
+GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path, bool isDirectory) {
// consolePrintf("'%s'",path.c_str());
char disp[128];
@@ -265,7 +274,7 @@ GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) {
strcpy(disp, pathStr + lastSlash + 1);
- _displayName = String(disp);
+ _displayName = Common::String(disp);
_path = path;
_isValid = true;
_isDirectory = isDirectory;
@@ -313,8 +322,8 @@ bool GBAMPFileSystemNode::getChildren(AbstractFSList& dirList, ListMode mode, bo
while (entryType != TYPE_NO_MORE) {
- if ( ((entryType == TYPE_DIR) && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)))
- || ((entryType == TYPE_FILE) && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll))) ) {
+ if ( ((entryType == TYPE_DIR) && ((mode == Common::FilesystemNode::kListDirectoriesOnly) || (mode == Common::FilesystemNode::kListAll)))
+ || ((entryType == TYPE_FILE) && ((mode == Common::FilesystemNode::kListFilesOnly) || (mode == Common::FilesystemNode::kListAll))) ) {
GBAMPFileSystemNode* dsfsn;
consolePrintf("Fname: %s\n", fname);
@@ -322,9 +331,9 @@ bool GBAMPFileSystemNode::getChildren(AbstractFSList& dirList, ListMode mode, bo
if (strcmp(fname, ".") && strcmp(fname, "..")) {
if (!strcmp(path, "/")) {
- dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String(fname), entryType == TYPE_DIR);
+ dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String(fname), entryType == TYPE_DIR);
} else {
- dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String("/") + String(fname), entryType == TYPE_DIR);
+ dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String("/") + Common::String(fname), entryType == TYPE_DIR);
}
// dsfsn->_isDirectory = entryType == DIR;
@@ -358,7 +367,7 @@ AbstractFilesystemNode* GBAMPFileSystemNode::getParent() const {
}
}
- p = new GBAMPFileSystemNode(String(path, lastSlash));
+ p = new GBAMPFileSystemNode(Common::String(path, lastSlash));
p->_isDirectory = true;
} else {
p = new GBAMPFileSystemNode();
@@ -367,6 +376,14 @@ AbstractFilesystemNode* GBAMPFileSystemNode::getParent() const {
return p;
}
+Common::SeekableReadStream *GBAMPFileSystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *GBAMPFileSystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
+
// Stdio replacements
#define MAX_FILE_HANDLES 32
@@ -399,6 +416,7 @@ FILE* std_fopen(const char* name, const char* mode) {
if (DS::isGBAMPAvailable()) {
FAT_chdir("/");
+ // Turn all back slashes into forward slashes for gba_nds_fat
char* p = realName;
while (*p) {
if (*p == '\\') *p = '/';
@@ -422,8 +440,12 @@ FILE* std_fopen(const char* name, const char* mode) {
// Allocate a file handle
int r = 0;
- while (handle[r].used) r++;
+ while (handle[r].used) {
+ r++;
+ assert(r < MAX_FILE_HANDLES);
+ }
+#ifdef GBA_SRAM_SAVE
if (strchr(mode, 'w')) {
// consolePrintf("Writing %s\n", realName);
handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true);
@@ -431,6 +453,7 @@ FILE* std_fopen(const char* name, const char* mode) {
// consolePrintf("Reading %s\n", realName);
handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false);
}
+#endif
if (handle[r].sramFile) {
handle[r].used = true;
@@ -512,69 +535,6 @@ size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) {
return bytes / size;
}
return numItems;
-
-/* int item = 0;
- u8* data = (u8 *) ptr;
- while ((item < numItems) && (!FAT_feof((FAT_FILE *) handle))) {
-
-
- int bytes = 0;
- while ((bytes < size) && (!FAT_feof((FAT_FILE *) handle))) {
- *data++ = FAT_fgetc((FAT_FILE *) handle);
- bytes++;
- }
-
- item++;
-
- }
-
- return item;
-*/
- int items = 0;
-
- //for (int r = 0; r < numItems; r++) {
- if (!std_feof(handle)) {
-/* for (int t = 0; t < size; t++) {
- if (feof(handle)) eof = true;
- *(((char *) (ptr)) + r * size + t) = getc(handle);
- }*/
- int left = size * numItems;
- int bytesRead = -1;
-
- while ((left > 0) && (!FAT_feof((FAT_FILE *) handle))) {
- int amount = left > 8192? 8192: left;
-// do {
- bytesRead = FAT_fread((void *) ptr, 1, amount, (FAT_FILE *) handle);
-/* if (bytesRead == 0) {
- consolePrintf("Pos:%d items:%d num:%d amount:%d read:%d\n", ftell(handle), items, numItems, amount, bytesRead);
- left++;
-
- int pos = ftell(handle);
-
- fseek(handle, 0, SEEK_SET);
- int c = getc(handle);
- fseek(handle, pos - 1024, SEEK_SET);
- fread(ptr, 1024, 1, handle);
- swiWaitForVBlank();
- //while (true);
- }
-
- } while (bytesRead == 0);
-*/
- left -= bytesRead;
- ptr = ((char *) (ptr)) + bytesRead;
- }
-
- items = numItems - (left / size);
-
-// FAT_fread((void *) ptr, size, 1, ((int) (handle)) - 1);
-// ptr = ((char *) (ptr)) + size;
- }
-// }
-
-// consolePrintf("...done %d \n", items)
-
- return items;
}
if (handle->sramFile) {
@@ -641,10 +601,6 @@ size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
}
}
-void std_fprintf(FILE* handle, const char* fmt, ...) {
- consolePrintf(fmt);
-}
-
bool std_feof(FILE* handle) {
// consolePrintf("feof ");
@@ -660,42 +616,10 @@ bool std_feof(FILE* handle) {
return handle->pos >= handle->size;
}
-void std_fflush(FILE* handle) {
+int std_fflush(FILE* handle) {
//FIXME: not implemented?
// consolePrintf("fflush ");
-}
-
-char* std_fgets(char* str, int size, FILE* file) {
-// consolePrintf("fgets file=%d ", file);
-
- if (DS::isGBAMPAvailable()) {
- char* s = str;
- while ((*s++ = std_getc(file)) >= 32) {
-// consolePrintf("%d ", *s);
- }
- *s = 0;
-
-// consolePrintf("Read:%s\n", str);
-
- return str;
- }
-
- if (file->sramFile) {
- file->pos--;
- int p = -1;
- do {
- file->pos++;
- p++;
- file->sramFile->read((char *) &str[p], 1);
-// consolePrintf("%d,", str[p]);
- } while ((str[p] >= 32) && (!std_feof(file)) && (p < size));
- str[p + 1] = 0;
- file->pos++;
-// consolePrintf("Read:%s\n", str);
- return str;
- }
-
- return NULL;
+ return 0;
}
long int std_ftell(FILE* handle) {
@@ -731,92 +655,20 @@ int std_fseek(FILE* handle, long int offset, int whence) {
return 0;
}
-void std_clearerr(FILE* handle) {
+int std_ferror(FILE* handle) {
//FIXME: not implemented?
-// consolePrintf("clearerr ");
-}
-
-int std_getc(FILE* handle) {
- if (DS::isGBAMPAvailable()) {
- char c;
- FAT_fread(&c, 1, 1, (FAT_FILE *) handle);
-
- return c;
- }
-
-// consolePrintf("fgetc ");
- return 0; // Not supported yet
+// consolePrintf("ferror ");
+ return 0;
}
-char* std_getcwd(char* dir, int dunno) {
-// consolePrintf("getcwd ");
- dir[0] = '\0';
- return dir; // Not supported yet
+void std_clearerr(FILE* handle) {
+ //FIXME: not implemented?
+// consolePrintf("clearerr ");
}
-void std_cwd(char* dir) {
- char buffer[128];
- strcpy(buffer, dir);
- char* realName = buffer;
-
- if (DS::isGBAMPAvailable()) {
- if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) {
- realName += 4;
- }
-
- // consolePrintf("Real cwd:%d\n", realName);
-
- char* p = realName;
- while (*p) {
- if (*p == '\\') *p = '/';
- p++;
- }
-
- // consolePrintf("Real cwd:%d\n", realName);
- FAT_chdir(realName);
- } else {
- if ((strlen(dir) >= 4) && (dir[0] == 'd') && (dir[1] == 's') && (dir[2] == ':') && (dir[3] == '/')) {
- realName += 4;
- }
-
- char* p = realName;
- while (*p) {
- if (*p == '\\') *p = '/';
- p++;
- }
-
- strcpy(currentDir, realName);
- if (*(currentDir + strlen(currentDir) - 1) == '/') {
- *(currentDir + strlen(currentDir) - 1) = '\0';
- }
-// consolePrintf("CWD: %s\n", currentDir);
- }
+void std_fprintf(FILE* handle, const char* fmt, ...) {
+ consolePrintf(fmt);
}
-int std_ferror(FILE* handle) {
- return 0;
-}
} // namespace DS
-
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/' && *cur != '\\') {
- --cur;
- }
-
- return cur + 1;
-}
-
diff --git a/backends/fs/ds/ds-fs.h b/backends/fs/ds/ds-fs.h
index 9ac453aca9..36e7bc9824 100644
--- a/backends/fs/ds/ds-fs.h
+++ b/backends/fs/ds/ds-fs.h
@@ -41,12 +41,10 @@ namespace DS {
*/
class DSFileSystemNode : public AbstractFilesystemNode {
protected:
- typedef class Common::String String;
-
static ZipFile* _zipFile;
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isValid;
@@ -61,7 +59,7 @@ public:
*
* @param path String with the path the new node should point to.
*/
- DSFileSystemNode(const String &path);
+ DSFileSystemNode(const Common::String &path);
/**
* Creates a DSFilesystemNode for a given path.
@@ -69,7 +67,7 @@ public:
* @param path String with the path the new node should point to.
* @param path true if path is a directory, false otherwise.
*/
- DSFileSystemNode(const String& path, bool isDir);
+ DSFileSystemNode(const Common::String& path, bool isDir);
/**
* Copy constructor.
@@ -77,9 +75,9 @@ public:
DSFileSystemNode(const DSFileSystemNode *node);
virtual bool exists() const { return true; } //FIXME: this is just a stub
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return true; } //FIXME: this is just a stub
virtual bool isWritable() const { return true; } //FIXME: this is just a stub
@@ -89,9 +87,12 @@ public:
*/
virtual AbstractFilesystemNode *clone() const { return new DSFileSystemNode(this); }
virtual AbstractFilesystemNode *getChild(const Common::String& name) const;
- virtual bool getChildren(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly, bool hidden = false) const;
+ virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
/**
* Returns the zip file this node points to.
* TODO: check this documentation.
@@ -107,10 +108,8 @@ public:
*/
class GBAMPFileSystemNode : public AbstractFilesystemNode {
protected:
- typedef class Common::String String;
-
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isValid;
@@ -125,7 +124,7 @@ public:
*
* @param path String with the path the new node should point to.
*/
- GBAMPFileSystemNode(const String &path);
+ GBAMPFileSystemNode(const Common::String &path);
/**
* Creates a DSFilesystemNode for a given path.
@@ -133,7 +132,7 @@ public:
* @param path String with the path the new node should point to.
* @param path true if path is a directory, false otherwise.
*/
- GBAMPFileSystemNode(const String &path, bool isDirectory);
+ GBAMPFileSystemNode(const Common::String &path, bool isDirectory);
/**
* Copy constructor.
@@ -141,9 +140,9 @@ public:
GBAMPFileSystemNode(const GBAMPFileSystemNode *node);
virtual bool exists() const { return _isValid || _isDirectory; }
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return true; } //FIXME: this is just a stub
virtual bool isWritable() const { return true; } //FIXME: this is just a stub
@@ -153,8 +152,11 @@ public:
*/
virtual AbstractFilesystemNode *clone() const { return new GBAMPFileSystemNode(this); }
virtual AbstractFilesystemNode *getChild(const Common::String& name) const;
- virtual bool getChildren(AbstractFSList &list, ListMode mode = FilesystemNode::kListDirectoriesOnly, bool hidden = false) const;
+ virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
};
struct fileHandle {
@@ -179,15 +181,14 @@ struct fileHandle {
// Please do not remove any of these prototypes that appear not to be required.
FILE* std_fopen(const char* name, const char* mode);
void std_fclose(FILE* handle);
-int std_getc(FILE* handle);
size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle);
size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle);
bool std_feof(FILE* handle);
long int std_ftell(FILE* handle);
int std_fseek(FILE* handle, long int offset, int whence);
void std_clearerr(FILE* handle);
-void std_cwd(char* dir);
-void std_fflush(FILE* handle);
+int std_fflush(FILE* handle);
+int std_ferror(FILE* handle);
} //namespace DS
diff --git a/backends/fs/palmos/palmos-fs-factory.cpp b/backends/fs/palmos/palmos-fs-factory.cpp
index 8699a9788b..bbc1639897 100644
--- a/backends/fs/palmos/palmos-fs-factory.cpp
+++ b/backends/fs/palmos/palmos-fs-factory.cpp
@@ -36,7 +36,7 @@ AbstractFilesystemNode *PalmOSFilesystemFactory::makeCurrentDirectoryFileNode()
return new PalmOSFilesystemNode();
}
-AbstractFilesystemNode *PalmOSFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *PalmOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new PalmOSFilesystemNode(path);
}
#endif
diff --git a/backends/fs/palmos/palmos-fs-factory.h b/backends/fs/palmos/palmos-fs-factory.h
index 3ea8b5fe47..f778aa89ef 100644
--- a/backends/fs/palmos/palmos-fs-factory.h
+++ b/backends/fs/palmos/palmos-fs-factory.h
@@ -35,11 +35,9 @@
*/
class PalmOSFilesystemFactory : public FilesystemFactory, public Common::Singleton<PalmOSFilesystemFactory> {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
protected:
PalmOSFilesystemFactory() {};
diff --git a/backends/fs/palmos/palmos-fs.cpp b/backends/fs/palmos/palmos-fs.cpp
index 5edb6c2d26..7c415aa320 100644
--- a/backends/fs/palmos/palmos-fs.cpp
+++ b/backends/fs/palmos/palmos-fs.cpp
@@ -28,6 +28,7 @@
#include "globals.h"
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
/**
* Implementation of the ScummVM file system API based on PalmOS VFS API.
@@ -36,8 +37,8 @@
*/
class PalmOSFilesystemNode : public AbstractFilesystemNode {
protected:
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isValid;
bool _isPseudoRoot;
@@ -51,22 +52,25 @@ public:
/**
* Creates a POSIXFilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
*/
- PalmOSFilesystemNode(const String &p);
+ PalmOSFilesystemNode(const Common::String &p);
virtual bool exists() const { return _isValid; }
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return true; } //FIXME: this is just a stub
virtual bool isWritable() const { return true; } //FIXME: this is just a stub
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
private:
/**
* Adds a single WindowsFilesystemNode to a given list.
@@ -74,44 +78,20 @@ private:
*
* @param list List to put the file entry node in.
* @param mode Mode to use while adding the file entry to the list.
- * @param base String with the directory being listed.
+ * @param base Common::String with the directory being listed.
* @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find.
*/
static void addFile(AbstractFSList &list, ListMode mode, const Char *base, FileInfoType* find_data);
};
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/') {
- --cur;
- }
-
- return cur + 1;
-}
-
void PalmOSFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, FileInfoType* find_data) {
PalmOSFilesystemNode entry;
bool isDir;
isDir = (find_data->attributes & vfsFileAttrDirectory);
- if ((!isDir && mode == FilesystemNode::kListDirectoriesOnly) ||
- (isDir && mode == FilesystemNode::kListFilesOnly))
+ if ((!isDir && mode == Common::FilesystemNode::kListDirectoriesOnly) ||
+ (isDir && mode == Common::FilesystemNode::kListFilesOnly))
return;
entry._isDirectory = isDir;
@@ -136,9 +116,9 @@ PalmOSFilesystemNode::PalmOSFilesystemNode() {
_isPseudoRoot = false;
}
-PalmOSFilesystemNode::PalmOSFilesystemNode(const String &p) {
+PalmOSFilesystemNode::PalmOSFilesystemNode(const Common::String &p) {
_path = p;
- _displayName = lastPathComponent(_path);
+ _displayName = lastPathComponent(_path, '/');
UInt32 attr;
FileRef handle;
@@ -159,10 +139,10 @@ PalmOSFilesystemNode::PalmOSFilesystemNode(const String &p) {
_isPseudoRoot = false;
}
-AbstractFilesystemNode *PalmOSFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *PalmOSFilesystemNode::getChild(const Common::String &n) const {
assert(_isDirectory);
- String newPath(_path);
+ Common::String newPath(_path);
if (_path.lastChar() != '/')
newPath += '/';
newPath += n;
@@ -215,17 +195,25 @@ AbstractFilesystemNode *PalmOSFilesystemNode::getParent() const {
if (!_isPseudoRoot) {
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '/');
p = new PalmOSFilesystemNode();
- p->_path = String(start, end - start);
+ p->_path = Common::String(start, end - start);
p->_isValid = true;
p->_isDirectory = true;
- p->_displayName = lastPathComponent(p->_path);
+ p->_displayName = lastPathComponent(p->_path, '/');
p->_isPseudoRoot =(p->_path == "/");
}
return p;
}
+Common::SeekableReadStream *PalmOSFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *PalmOSFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
+
#endif // PALMOS_MODE
diff --git a/backends/fs/posix/posix-fs-factory.cpp b/backends/fs/posix/posix-fs-factory.cpp
index 0a1160ff8f..cbfb69b76a 100644
--- a/backends/fs/posix/posix-fs-factory.cpp
+++ b/backends/fs/posix/posix-fs-factory.cpp
@@ -26,19 +26,18 @@
#include "backends/fs/posix/posix-fs-factory.h"
#include "backends/fs/posix/posix-fs.cpp"
-DECLARE_SINGLETON(POSIXFilesystemFactory);
-
AbstractFilesystemNode *POSIXFilesystemFactory::makeRootFileNode() const {
- return new POSIXFilesystemNode();
+ return new POSIXFilesystemNode("/");
}
AbstractFilesystemNode *POSIXFilesystemFactory::makeCurrentDirectoryFileNode() const {
char buf[MAXPATHLEN];
getcwd(buf, MAXPATHLEN);
- return new POSIXFilesystemNode(buf, true);
+ return new POSIXFilesystemNode(buf);
}
-AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const String &path) const {
- return new POSIXFilesystemNode(path, true);
+AbstractFilesystemNode *POSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const {
+ assert(!path.empty());
+ return new POSIXFilesystemNode(path);
}
#endif
diff --git a/backends/fs/posix/posix-fs-factory.h b/backends/fs/posix/posix-fs-factory.h
index d8eecda6ef..c697679814 100644
--- a/backends/fs/posix/posix-fs-factory.h
+++ b/backends/fs/posix/posix-fs-factory.h
@@ -25,7 +25,6 @@
#ifndef POSIX_FILESYSTEM_FACTORY_H
#define POSIX_FILESYSTEM_FACTORY_H
-#include "common/singleton.h"
#include "backends/fs/fs-factory.h"
/**
@@ -33,19 +32,10 @@
*
* Parts of this class are documented in the base interface class, FilesystemFactory.
*/
-class POSIXFilesystemFactory : public FilesystemFactory, public Common::Singleton<POSIXFilesystemFactory> {
-public:
- typedef Common::String String;
-
+class POSIXFilesystemFactory : public FilesystemFactory {
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
-
-protected:
- POSIXFilesystemFactory() {};
-
-private:
- friend class Common::Singleton<SingletonBaseType>;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
};
#endif /*POSIX_FILESYSTEM_FACTORY_H*/
diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp
index 5cde32c851..8dca78d82a 100644
--- a/backends/fs/posix/posix-fs.cpp
+++ b/backends/fs/posix/posix-fs.cpp
@@ -24,85 +24,20 @@
#if defined(UNIX)
-#include "backends/fs/abstract-fs.h"
+#include "backends/fs/posix/posix-fs.h"
+#include "backends/fs/stdiostream.h"
+#include "common/algorithm.h"
-#ifdef MACOSX
-#include <sys/types.h>
-#endif
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
-#include <unistd.h>
-/**
- * Implementation of the ScummVM file system API based on POSIX.
- *
- * Parts of this class are documented in the base interface class, AbstractFilesystemNode.
- */
-class POSIXFilesystemNode : public AbstractFilesystemNode {
-protected:
- String _displayName;
- String _path;
- bool _isDirectory;
- bool _isValid;
-
-public:
- /**
- * Creates a POSIXFilesystemNode with the root node as path.
- */
- POSIXFilesystemNode();
-
- /**
- * Creates a POSIXFilesystemNode for a given path.
- *
- * @param path String with the path the new node should point to.
- * @param verify true if the isValid and isDirectory flags should be verified during the construction.
- */
- POSIXFilesystemNode(const String &path, bool verify);
-
- virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; }
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
- virtual bool isDirectory() const { return _isDirectory; }
- virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; }
- virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; }
-
- virtual AbstractFilesystemNode *getChild(const String &n) const;
- virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
- virtual AbstractFilesystemNode *getParent() const;
-
-private:
- /**
- * Tests and sets the _isValid and _isDirectory flags, using the stat() function.
- */
- virtual void setFlags();
-};
-
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/') {
- --cur;
- }
+#ifdef __OS2__
+#define INCL_DOS
+#include <os2.h>
+#endif
- return cur + 1;
-}
void POSIXFilesystemNode::setFlags() {
struct stat st;
@@ -111,15 +46,7 @@ void POSIXFilesystemNode::setFlags() {
_isDirectory = _isValid ? S_ISDIR(st.st_mode) : false;
}
-POSIXFilesystemNode::POSIXFilesystemNode() {
- // The root dir.
- _path = "/";
- _displayName = _path;
- _isValid = true;
- _isDirectory = true;
-}
-
-POSIXFilesystemNode::POSIXFilesystemNode(const String &p, bool verify) {
+POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p) {
assert(p.size() > 0);
// Expand "~/" to the value of the HOME env variable
@@ -134,30 +61,85 @@ POSIXFilesystemNode::POSIXFilesystemNode(const String &p, bool verify) {
} else {
_path = p;
}
-
- _displayName = lastPathComponent(_path);
-
- if (verify) {
- setFlags();
+
+#ifdef __OS2__
+ // On OS/2, 'X:/' is a root of drive X, so we should not remove that last
+ // slash.
+ if (!(_path.size() == 3 && _path.hasSuffix(":/")))
+#endif
+ // Normalize the path (that is, remove unneeded slashes etc.)
+ _path = Common::normalizePath(_path, '/');
+ _displayName = Common::lastPathComponent(_path, '/');
+
+ // TODO: should we turn relative paths into absolute ones?
+ // Pro: Ensures the "getParent" works correctly even for relative dirs.
+ // Contra: The user may wish to use (and keep!) relative paths in his
+ // config file, and converting relative to absolute paths may hurt him...
+ //
+ // An alternative approach would be to change getParent() to work correctly
+ // if "_path" is the empty string.
+#if 0
+ if (!_path.hasPrefix("/")) {
+ char buf[MAXPATHLEN+1];
+ getcwd(buf, MAXPATHLEN);
+ strcat(buf, "/");
+ _path = buf + _path;
}
+#endif
+ // TODO: Should we enforce that the path is absolute at this point?
+ //assert(_path.hasPrefix("/"));
+
+ setFlags();
}
-AbstractFilesystemNode *POSIXFilesystemNode::getChild(const String &n) const {
- // FIXME: Pretty lame implementation! We do no error checking to speak
- // of, do not check if this is a special node, etc.
+AbstractFilesystemNode *POSIXFilesystemNode::getChild(const Common::String &n) const {
+ assert(!_path.empty());
assert(_isDirectory);
+
+ // Make sure the string contains no slashes
+ assert(!n.contains('/'));
- String newPath(_path);
+ // We assume here that _path is already normalized (hence don't bother to call
+ // Common::normalizePath on the final path).
+ Common::String newPath(_path);
if (_path.lastChar() != '/')
newPath += '/';
newPath += n;
- return new POSIXFilesystemNode(newPath, true);
+ return makeNode(newPath);
}
bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
assert(_isDirectory);
+#ifdef __OS2__
+ if (_path == "/") {
+ // Special case for the root dir: List all DOS drives
+ ULONG ulDrvNum;
+ ULONG ulDrvMap;
+
+ DosQueryCurrentDisk(&ulDrvNum, &ulDrvMap);
+
+ for (int i = 0; i < 26; i++) {
+ if (ulDrvMap & 1) {
+ char drive_root[] = "A:/";
+ drive_root[0] += i;
+
+ POSIXFilesystemNode *entry = new POSIXFilesystemNode();
+ entry->_isDirectory = true;
+ entry->_isValid = true;
+ entry->_path = drive_root;
+ entry->_displayName = "[" + Common::String(drive_root, 2) + "]";
+ myList.push_back(entry);
+ }
+
+ ulDrvMap >>= 1;
+ }
+
+ return true;
+ }
+#endif
+
DIR *dirp = opendir(_path.c_str());
struct dirent *dp;
@@ -175,12 +157,12 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo
continue;
}
- String newPath(_path);
- if (newPath.lastChar() != '/')
- newPath += '/';
- newPath += dp->d_name;
-
- POSIXFilesystemNode entry(newPath, false);
+ // Start with a clone of this node, with the correct path set
+ POSIXFilesystemNode entry(*this);
+ entry._displayName = dp->d_name;
+ if (_path.lastChar() != '/')
+ entry._path += '/';
+ entry._path += entry._displayName;
#if defined(SYSTEM_NOT_SUPPORTING_D_TYPE)
/* TODO: d_type is not part of POSIX, so it might not be supported
@@ -215,13 +197,10 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo
continue;
// Honor the chosen mode
- if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) ||
- (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
+ if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) ||
+ (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
continue;
- if (entry._isDirectory)
- entry._path += "/";
-
myList.push_back(new POSIXFilesystemNode(entry));
}
closedir(dirp);
@@ -231,12 +210,39 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo
AbstractFilesystemNode *POSIXFilesystemNode::getParent() const {
if (_path == "/")
- return 0;
+ return 0; // The filesystem root has no parent
+
+#ifdef __OS2__
+ if (_path.size() == 3 && _path.hasSuffix(":/"))
+ // This is a root directory of a drive
+ return makeNode("/"); // return a virtual root for a list of drives
+#endif
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = start + _path.size();
+
+ // Strip of the last component. We make use of the fact that at this
+ // point, _path is guaranteed to be normalized
+ while (end > start && *(end-1) != '/')
+ end--;
+
+ if (end == start) {
+ // This only happens if we were called with a relative path, for which
+ // there simply is no parent.
+ // TODO: We could also resolve this by assuming that the parent is the
+ // current working directory, and returning a node referring to that.
+ return 0;
+ }
+
+ return makeNode(Common::String(start, end));
+}
+
+Common::SeekableReadStream *POSIXFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
- return new POSIXFilesystemNode(String(start, end - start), true);
+Common::WriteStream *POSIXFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
}
#endif //#if defined(UNIX)
diff --git a/backends/fs/posix/posix-fs.h b/backends/fs/posix/posix-fs.h
new file mode 100644
index 0000000000..e09e433e05
--- /dev/null
+++ b/backends/fs/posix/posix-fs.h
@@ -0,0 +1,86 @@
+/* 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 POSIX_FILESYSTEM_H
+#define POSIX_FILESYSTEM_H
+
+#include "backends/fs/abstract-fs.h"
+
+#ifdef MACOSX
+#include <sys/types.h>
+#endif
+#include <unistd.h>
+
+/**
+ * Implementation of the ScummVM file system API based on POSIX.
+ *
+ * Parts of this class are documented in the base interface class, AbstractFilesystemNode.
+ */
+class POSIXFilesystemNode : public AbstractFilesystemNode {
+protected:
+ Common::String _displayName;
+ Common::String _path;
+ bool _isDirectory;
+ bool _isValid;
+
+ virtual AbstractFilesystemNode *makeNode(const Common::String &path) const {
+ return new POSIXFilesystemNode(path);
+ }
+
+ /**
+ * Plain constructor, for internal use only (hence protected).
+ */
+ POSIXFilesystemNode() : _isDirectory(false), _isValid(false) {}
+
+public:
+ /**
+ * Creates a POSIXFilesystemNode for a given path.
+ *
+ * @param path the path the new node should point to.
+ */
+ POSIXFilesystemNode(const Common::String &path);
+
+ virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
+ virtual bool isDirectory() const { return _isDirectory; }
+ virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; }
+ virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; }
+
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
+ virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
+ virtual AbstractFilesystemNode *getParent() const;
+
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
+private:
+ /**
+ * Tests and sets the _isValid and _isDirectory flags, using the stat() function.
+ */
+ virtual void setFlags();
+};
+
+#endif /*POSIX_FILESYSTEM_H*/
diff --git a/backends/fs/ps2/ps2-fs-factory.cpp b/backends/fs/ps2/ps2-fs-factory.cpp
index ce3b4a5eaf..e96671ee0a 100644
--- a/backends/fs/ps2/ps2-fs-factory.cpp
+++ b/backends/fs/ps2/ps2-fs-factory.cpp
@@ -36,7 +36,7 @@ AbstractFilesystemNode *Ps2FilesystemFactory::makeCurrentDirectoryFileNode() con
return new Ps2FilesystemNode();
}
-AbstractFilesystemNode *Ps2FilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *Ps2FilesystemFactory::makeFileNodePath(const Common::String &path) const {
// return new Ps2FilesystemNode(path);
Ps2FilesystemNode *nf = new Ps2FilesystemNode(path, true);
diff --git a/backends/fs/ps2/ps2-fs-factory.h b/backends/fs/ps2/ps2-fs-factory.h
index 416024c905..432cf467c3 100644
--- a/backends/fs/ps2/ps2-fs-factory.h
+++ b/backends/fs/ps2/ps2-fs-factory.h
@@ -35,11 +35,9 @@
*/
class Ps2FilesystemFactory : public FilesystemFactory, public Common::Singleton<Ps2FilesystemFactory> {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
protected:
Ps2FilesystemFactory() {};
diff --git a/backends/fs/ps2/ps2-fs.cpp b/backends/fs/ps2/ps2-fs.cpp
index 782e97b959..3d7656e9f0 100644
--- a/backends/fs/ps2/ps2-fs.cpp
+++ b/backends/fs/ps2/ps2-fs.cpp
@@ -23,6 +23,7 @@
*/
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#include <kernel.h>
#include <stdio.h>
#include <stdlib.h>
@@ -47,8 +48,8 @@ class Ps2FilesystemNode : public AbstractFilesystemNode {
friend class Ps2FilesystemFactory;
protected:
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isRoot;
@@ -65,10 +66,10 @@ public:
/**
* Creates a PS2FilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
*/
- Ps2FilesystemNode(const String &path);
- Ps2FilesystemNode(const String &path, bool verify);
+ Ps2FilesystemNode(const Common::String &path);
+ Ps2FilesystemNode(const Common::String &path, bool verify);
/**
* Copy constructor.
@@ -77,9 +78,9 @@ public:
virtual bool exists(void) const;
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const {
return _isDirectory;
@@ -95,32 +96,13 @@ public:
}
virtual AbstractFilesystemNode *clone() const { return new Ps2FilesystemNode(this); }
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
-};
-
-/**
- * Returns the last component of a given path.
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if (str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/' && *cur != ':') {
- --cur;
- }
-
- printf("romeo : lastPathComponent = %s\n", cur + 1);
- return cur + 1;
-}
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+};
Ps2FilesystemNode::Ps2FilesystemNode() {
_isDirectory = true;
@@ -129,12 +111,12 @@ Ps2FilesystemNode::Ps2FilesystemNode() {
_path = "";
}
-Ps2FilesystemNode::Ps2FilesystemNode(const String &path) {
+Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path) {
_path = path;
_isDirectory = true;
if (strcmp(path.c_str(), "") == 0) {
_isRoot = true;
- _displayName = String("PlayStation 2");
+ _displayName = Common::String("PlayStation 2");
} else {
_isRoot = false;
const char *dsplName = NULL, *pos = path.c_str();
@@ -142,18 +124,18 @@ Ps2FilesystemNode::Ps2FilesystemNode(const String &path) {
if (*pos++ == '/')
dsplName = pos;
if (dsplName)
- _displayName = String(dsplName);
+ _displayName = Common::String(dsplName);
else
_displayName = getDeviceDescription(path.c_str());
}
}
-Ps2FilesystemNode::Ps2FilesystemNode(const String &path, bool verify) {
+Ps2FilesystemNode::Ps2FilesystemNode(const Common::String &path, bool verify) {
_path = path;
if (strcmp(path.c_str(), "") == 0) {
_isRoot = true; /* root is always a dir*/
- _displayName = String("PlayStation 2");
+ _displayName = Common::String("PlayStation 2");
_isDirectory = true;
} else {
_isRoot = false;
@@ -163,7 +145,7 @@ Ps2FilesystemNode::Ps2FilesystemNode(const String &path, bool verify) {
dsplName = pos;
if (dsplName) {
- _displayName = String(dsplName);
+ _displayName = Common::String(dsplName);
if (verify)
_isDirectory = getDirectoryFlag(path.c_str());
else
@@ -228,7 +210,7 @@ bool Ps2FilesystemNode::getDirectoryFlag(const char *path) {
return false;
}
-AbstractFilesystemNode *Ps2FilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *Ps2FilesystemNode::getChild(const Common::String &n) const {
if (!_isDirectory)
return NULL;
@@ -306,9 +288,9 @@ bool Ps2FilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hi
while ((dreadRes = fio.dread(fd, &dirent)) > 0) {
if (dirent.name[0] == '.')
continue; // ignore '.' and '..'
- if (((mode == FilesystemNode::kListDirectoriesOnly) && (dirent.stat.mode & FIO_S_IFDIR)) ||
- ((mode == FilesystemNode::kListFilesOnly) && !(dirent.stat.mode & FIO_S_IFDIR)) ||
- (mode == FilesystemNode::kListAll)) {
+ if (((mode == Common::FilesystemNode::kListDirectoriesOnly) && (dirent.stat.mode & FIO_S_IFDIR)) ||
+ ((mode == Common::FilesystemNode::kListFilesOnly) && !(dirent.stat.mode & FIO_S_IFDIR)) ||
+ (mode == Common::FilesystemNode::kListAll)) {
dirEntry._isDirectory = (bool)(dirent.stat.mode & FIO_S_IFDIR);
dirEntry._isRoot = false;
@@ -344,7 +326,7 @@ AbstractFilesystemNode *Ps2FilesystemNode::getParent() const {
}
if (slash)
- return new Ps2FilesystemNode(String(_path.c_str(), slash - _path.c_str()));
+ return new Ps2FilesystemNode(Common::String(_path.c_str(), slash - _path.c_str()));
else
return new Ps2FilesystemNode();
}
@@ -359,3 +341,10 @@ char *Ps2FilesystemNode::getDeviceDescription(const char *path) const {
return "Harddisk";
}
+Common::SeekableReadStream *Ps2FilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *Ps2FilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
diff --git a/backends/fs/psp/psp-fs-factory.cpp b/backends/fs/psp/psp-fs-factory.cpp
index 87f0e0f587..a38462f02a 100644
--- a/backends/fs/psp/psp-fs-factory.cpp
+++ b/backends/fs/psp/psp-fs-factory.cpp
@@ -36,7 +36,7 @@ AbstractFilesystemNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() con
return new PSPFilesystemNode();
}
-AbstractFilesystemNode *PSPFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new PSPFilesystemNode(path, true);
}
#endif
diff --git a/backends/fs/psp/psp-fs-factory.h b/backends/fs/psp/psp-fs-factory.h
index ffa934755f..abf03d288e 100644
--- a/backends/fs/psp/psp-fs-factory.h
+++ b/backends/fs/psp/psp-fs-factory.h
@@ -35,11 +35,9 @@
*/
class PSPFilesystemFactory : public FilesystemFactory, public Common::Singleton<PSPFilesystemFactory> {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
protected:
PSPFilesystemFactory() {};
diff --git a/backends/fs/psp/psp-fs.cpp b/backends/fs/psp/psp-fs.cpp
index 3fe6060928..13cd63903b 100644
--- a/backends/fs/psp/psp-fs.cpp
+++ b/backends/fs/psp/psp-fs.cpp
@@ -26,6 +26,7 @@
#include "engines/engine.h"
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#include <sys/stat.h>
#include <unistd.h>
@@ -39,8 +40,8 @@
*/
class PSPFilesystemNode : public AbstractFilesystemNode {
protected:
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isValid;
@@ -53,47 +54,26 @@ public:
/**
* Creates a PSPFilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
* @param verify true if the isValid and isDirectory flags should be verified during the construction.
*/
PSPFilesystemNode(const Common::String &p, bool verify);
virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; }
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; }
virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; }
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
-};
-
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/') {
- --cur;
- }
-
- return cur + 1;
-}
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+};
PSPFilesystemNode::PSPFilesystemNode() {
_isDirectory = true;
@@ -106,7 +86,7 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) {
assert(p.size() > 0);
_path = p;
- _displayName = lastPathComponent(_path);
+ _displayName = lastPathComponent(_path, '/');
_isValid = true;
_isDirectory = true;
@@ -117,12 +97,12 @@ PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) {
}
}
-AbstractFilesystemNode *PSPFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *PSPFilesystemNode::getChild(const Common::String &n) const {
// FIXME: Pretty lame implementation! We do no error checking to speak
// of, do not check if this is a special node, etc.
assert(_isDirectory);
- String newPath(_path);
+ Common::String newPath(_path);
if (_path.lastChar() != '/')
newPath += '/';
newPath += n;
@@ -157,8 +137,8 @@ bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
entry._path += "/";
// Honor the chosen mode
- if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) ||
- (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
+ if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) ||
+ (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
continue;
myList.push_back(new PSPFilesystemNode(entry));
@@ -176,9 +156,17 @@ AbstractFilesystemNode *PSPFilesystemNode::getParent() const {
return 0;
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '/');
+
+ return new PSPFilesystemNode(Common::String(start, end - start), false);
+}
+
+Common::SeekableReadStream *PSPFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
- return new PSPFilesystemNode(String(start, end - start), false);
+Common::WriteStream *PSPFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
}
#endif //#ifdef __PSP__
diff --git a/backends/fs/stdiostream.cpp b/backends/fs/stdiostream.cpp
new file mode 100644
index 0000000000..3b0de253ab
--- /dev/null
+++ b/backends/fs/stdiostream.cpp
@@ -0,0 +1,161 @@
+/* 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 "backends/fs/stdiostream.h"
+
+#include <errno.h>
+
+#if defined(MACOSX) || defined(IPHONE)
+#include "CoreFoundation/CoreFoundation.h"
+#endif
+
+
+#ifdef __PLAYSTATION2__
+ // for those replaced fopen/fread/etc functions
+ typedef unsigned long uint64;
+ typedef signed long int64;
+ #include "backends/platform/ps2/fileio.h"
+
+ #define fopen(a, b) ps2_fopen(a, b)
+ #define fclose(a) ps2_fclose(a)
+ #define fseek(a, b, c) ps2_fseek(a, b, c)
+ #define ftell(a) ps2_ftell(a)
+ #define feof(a) ps2_feof(a)
+ #define fread(a, b, c, d) ps2_fread(a, b, c, d)
+ #define fwrite(a, b, c, d) ps2_fwrite(a, b, c, d)
+
+ //#define fprintf ps2_fprintf // used in common/util.cpp
+ //#define fflush(a) ps2_fflush(a) // used in common/util.cpp
+
+ //#define fgetc(a) ps2_fgetc(a) // not used
+ //#define fgets(a, b, c) ps2_fgets(a, b, c) // not used
+ //#define fputc(a, b) ps2_fputc(a, b) // not used
+ //#define fputs(a, b) ps2_fputs(a, b) // not used
+
+ //#define fsize(a) ps2_fsize(a) // not used -- and it is not a standard function either
+#endif
+
+#ifdef __DS__
+
+ // These functions replace the standard library functions of the same name.
+ // As this header is included after the standard one, I have the chance to #define
+ // all of these to my own code.
+ //
+ // A #define is the only way, as redefinig the functions would cause linker errors.
+
+ // These functions need to be #undef'ed, as their original definition
+ // in devkitarm is done with #includes (ugh!)
+ #undef feof
+ #undef clearerr
+ //#undef getc
+ //#undef ferror
+
+ #include "backends/fs/ds/ds-fs.h"
+
+
+ // Only functions used in the ScummVM source have been defined here!
+ #define fopen(name, mode) DS::std_fopen(name, mode)
+ #define fclose(handle) DS::std_fclose(handle)
+ #define fread(ptr, size, items, file) DS::std_fread(ptr, size, items, file)
+ #define fwrite(ptr, size, items, file) DS::std_fwrite(ptr, size, items, file)
+ #define feof(handle) DS::std_feof(handle)
+ #define ftell(handle) DS::std_ftell(handle)
+ #define fseek(handle, offset, whence) DS::std_fseek(handle, offset, whence)
+ #define clearerr(handle) DS::std_clearerr(handle)
+ #define fflush(file) DS::std_fflush(file)
+ #define ferror(handle) DS::std_ferror(handle)
+
+#endif
+
+StdioStream::StdioStream(void *handle) : _handle(handle) {
+ assert(handle);
+}
+
+StdioStream::~StdioStream() {
+ fclose((FILE *)_handle);
+}
+
+bool StdioStream::err() const {
+ return ferror((FILE *)_handle) != 0;
+}
+
+void StdioStream::clearErr() {
+ clearerr((FILE *)_handle);
+}
+
+bool StdioStream::eos() const {
+ return feof((FILE *)_handle) != 0;
+}
+
+int32 StdioStream::pos() const {
+ return ftell((FILE *)_handle);
+}
+
+int32 StdioStream::size() const {
+ int32 oldPos = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, 0, SEEK_END);
+ int32 length = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, oldPos, SEEK_SET);
+
+ return length;
+}
+
+bool StdioStream::seek(int32 offs, int whence) {
+ return fseek((FILE *)_handle, offs, whence) == 0;
+}
+
+uint32 StdioStream::read(void *ptr, uint32 len) {
+ return fread((byte *)ptr, 1, len, (FILE *)_handle);
+}
+
+uint32 StdioStream::write(const void *ptr, uint32 len) {
+ return fwrite(ptr, 1, len, (FILE *)_handle);
+}
+
+bool StdioStream::flush() {
+ return fflush((FILE *)_handle) == 0;
+}
+
+StdioStream *StdioStream::makeFromPath(const Common::String &path, bool writeMode) {
+ FILE *handle = fopen(path.c_str(), writeMode ? "wb" : "rb");
+
+#ifdef __amigaos4__
+ //
+ // Work around for possibility that someone uses AmigaOS "newlib" build
+ // with SmartFileSystem (blocksize 512 bytes), leading to buffer size
+ // being only 512 bytes. "Clib2" sets the buffer size to 8KB, resulting
+ // smooth movie playback. This forces the buffer to be enough also when
+ // using "newlib" compile on SFS.
+ //
+ if (handle && !writeMode) {
+ setvbuf(handle, NULL, _IOFBF, 8192);
+ }
+#endif
+
+
+ if (handle)
+ return new StdioStream(handle);
+ return 0;
+}
diff --git a/engines/scumm/smush/chunk.h b/backends/fs/stdiostream.h
index ca4a3cdd99..3d44062d7f 100644
--- a/engines/scumm/smush/chunk.h
+++ b/backends/fs/stdiostream.h
@@ -23,70 +23,40 @@
*
*/
-#ifndef SCUMM_SMUSH_CHUNK_H
-#define SCUMM_SMUSH_CHUNK_H
+#ifndef BACKENDS_FS_STDIOSTREAM_H
+#define BACKENDS_FS_STDIOSTREAM_H
#include "common/scummsys.h"
-#include "common/str.h"
+#include "common/noncopyable.h"
#include "common/stream.h"
+#include "common/str.h"
-namespace Scumm {
-
-class BaseScummFile;
-
-class Chunk : public Common::SeekableReadStream {
-public:
- typedef uint32 type;
-
- virtual type getType() const = 0;
- virtual Chunk *subBlock() = 0;
- virtual void reseek() = 0;
-};
-
-// Common functionality for concrete chunks (FileChunk, MemoryChunk)
-class BaseChunk : public Chunk {
+class StdioStream : public Common::SeekableReadStream, public Common::WriteStream, public Common::NonCopyable {
protected:
- Chunk::type _type;
- uint32 _size;
- uint32 _curPos;
- Common::String _name;
-
- BaseChunk();
+ /** File handle to the actual file. */
+ void *_handle;
public:
- Chunk::type getType() const;
- uint32 size() const;
- bool eos() const;
- uint32 pos() const;
- void seek(int32 delta, int dir);
-};
+ /**
+ * Given a path, invokes fopen on that path and wrap the result in a
+ * StdioStream instance.
+ */
+ static StdioStream *makeFromPath(const Common::String &path, bool writeMode);
-class FileChunk : public BaseChunk {
-private:
- BaseScummFile *_data;
- bool _deleteData;
- uint32 _offset;
+ StdioStream(void *handle);
+ virtual ~StdioStream();
- FileChunk(BaseScummFile *data, int offset);
-public:
- FileChunk(const Common::String &name, int offset = 0);
- virtual ~FileChunk();
- Chunk *subBlock();
- void reseek();
- uint32 read(void *buffer, uint32 size);
-};
+ bool err() const;
+ void clearErr();
+ bool eos() const;
-class MemoryChunk : public BaseChunk {
-private:
- byte *_data;
+ virtual uint32 write(const void *dataPtr, uint32 dataSize);
+ virtual bool flush();
-public:
- MemoryChunk(byte *data);
- Chunk *subBlock();
- void reseek();
- uint32 read(void *buffer, uint32 size);
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ bool seek(int32 offs, int whence = SEEK_SET);
+ uint32 read(void *dataPtr, uint32 dataSize);
};
-} // End of namespace Scumm
-
#endif
diff --git a/backends/fs/symbian/symbian-fs-factory.cpp b/backends/fs/symbian/symbian-fs-factory.cpp
index 0a1bd62134..c31dfb594a 100644
--- a/backends/fs/symbian/symbian-fs-factory.cpp
+++ b/backends/fs/symbian/symbian-fs-factory.cpp
@@ -26,8 +26,6 @@
#include "backends/fs/symbian/symbian-fs-factory.h"
#include "backends/fs/symbian/symbian-fs.cpp"
-DECLARE_SINGLETON(SymbianFilesystemFactory);
-
AbstractFilesystemNode *SymbianFilesystemFactory::makeRootFileNode() const {
return new SymbianFilesystemNode(true);
}
@@ -38,7 +36,7 @@ AbstractFilesystemNode *SymbianFilesystemFactory::makeCurrentDirectoryFileNode()
return new SymbianFilesystemNode(path);
}
-AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *SymbianFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new SymbianFilesystemNode(path);
}
#endif
diff --git a/backends/fs/symbian/symbian-fs-factory.h b/backends/fs/symbian/symbian-fs-factory.h
index 502fba2930..ef5a231e72 100644
--- a/backends/fs/symbian/symbian-fs-factory.h
+++ b/backends/fs/symbian/symbian-fs-factory.h
@@ -25,7 +25,6 @@
#ifndef SYMBIAN_FILESYSTEM_FACTORY_H
#define SYMBIAN_FILESYSTEM_FACTORY_H
-#include "common/singleton.h"
#include "backends/fs/fs-factory.h"
/**
@@ -33,19 +32,11 @@
*
* Parts of this class are documented in the base interface class, FilesystemFactory.
*/
-class SymbianFilesystemFactory : public FilesystemFactory, public Common::Singleton<SymbianFilesystemFactory> {
+class SymbianFilesystemFactory : public FilesystemFactory {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
-
-protected:
- SymbianFilesystemFactory() {};
-
-private:
- friend class Common::Singleton<SingletonBaseType>;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
};
#endif /*SYMBIAN_FILESYSTEM_FACTORY_H*/
diff --git a/backends/fs/symbian/symbian-fs.cpp b/backends/fs/symbian/symbian-fs.cpp
index 85fc58179a..1c6d8435a9 100644
--- a/backends/fs/symbian/symbian-fs.cpp
+++ b/backends/fs/symbian/symbian-fs.cpp
@@ -24,12 +24,16 @@
#if defined (__SYMBIAN32__)
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/symbian/symbianstream.h"
+#include "backends/platform/symbian/src/symbianos.h"
#include <dirent.h>
#include <eikenv.h>
#include <f32file.h>
#include <bautils.h>
+#define KDriveLabelSize 30
+
/**
* Implementation of the ScummVM file system API based on POSIX.
*
@@ -37,12 +41,11 @@
*/
class SymbianFilesystemNode : public AbstractFilesystemNode {
protected:
- String _displayName;
- String _path;
- bool _isDirectory;
- bool _isValid;
- bool _isPseudoRoot;
-
+ Common::String _displayName;
+ Common::String _path;
+ TBool _isDirectory;
+ TBool _isValid;
+ TBool _isPseudoRoot;
public:
/**
* Creates a SymbianFilesystemNode with the root node as path.
@@ -54,57 +57,36 @@ public:
/**
* Creates a SymbianFilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
*/
- SymbianFilesystemNode(const String &path);
+ SymbianFilesystemNode(const Common::String &path);
virtual bool exists() const {
TFileName fname;
- TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size());
+ TPtrC8 ptr((const unsigned char*) _path.c_str(), _path.size());
fname.Copy(ptr);
- TBool fileExists = BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), fname);
+ TBool fileExists = BaflUtils::FileExists(static_cast<OSystem_SDL_Symbian*> (g_system)->FsSession(), fname);
return fileExists;
}
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } //FIXME: this is just a stub
virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } //FIXME: this is just a stub
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
-};
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * c:\foo\bar.txt would return "\bar.txt"
- * c:\foo\bar\ would return "\bar\"
- *
- * @param str Path to obtain the last component from.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '\\') {
- --cur;
- }
-
- return cur + 1;
-}
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+};
/**
* Fixes the path by changing all slashes to backslashes.
*
- * @param path String with the path to be fixed.
+ * @param path Common::String with the path to be fixed.
*/
static void fixFilePath(Common::String& aPath){
TInt len = aPath.size();
@@ -118,54 +100,47 @@ static void fixFilePath(Common::String& aPath){
SymbianFilesystemNode::SymbianFilesystemNode(bool aIsRoot) {
_path = "";
- _isValid = true;
- _isDirectory = true;
+ _isValid = ETrue;
+ _isDirectory = ETrue;
_isPseudoRoot = aIsRoot;
_displayName = "Root";
}
-SymbianFilesystemNode::SymbianFilesystemNode(const String &path) {
+SymbianFilesystemNode::SymbianFilesystemNode(const Common::String &path) {
if (path.size() == 0)
- _isPseudoRoot = true;
+ _isPseudoRoot = ETrue;
else
- _isPseudoRoot = false;
+ _isPseudoRoot = EFalse;
_path = path;
fixFilePath(_path);
- _displayName = lastPathComponent(_path);
+ _displayName = lastPathComponent(_path, '\\');
TEntry fileAttribs;
TFileName fname;
TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size());
fname.Copy(ptr);
- if (CEikonEnv::Static()->FsSession().Entry(fname, fileAttribs) == KErrNone) {
- _isValid = true;
+ if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().Entry(fname, fileAttribs) == KErrNone) {
+ _isValid = ETrue;
_isDirectory = fileAttribs.IsDir();
} else {
- _isValid = false;
- _isDirectory = false;
+ _isValid = ETrue;
+ _isDirectory = EFalse;
}
}
-AbstractFilesystemNode *SymbianFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *SymbianFilesystemNode::getChild(const Common::String &n) const {
assert(_isDirectory);
- String newPath(_path);
+ Common::String newPath(_path);
if (_path.lastChar() != '\\')
newPath += '\\';
- newPath += n;
- TPtrC8 ptr((const unsigned char*) newPath.c_str(), newPath.size());
- TFileName fname;
- fname.Copy(ptr);
- TBool isFolder = EFalse;
- BaflUtils::IsFolder(CEikonEnv::Static()->FsSession(), fname, isFolder);
- if (!isFolder)
- return 0;
+ newPath += n;
return new SymbianFilesystemNode(newPath);
}
@@ -177,19 +152,19 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
if (_isPseudoRoot) {
// Drives enumeration
- RFs fs = CEikonEnv::Static()->FsSession();
+ RFs& fs = static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession();
TInt driveNumber;
TChar driveLetter;
TUint driveLetterValue;
TVolumeInfo volumeInfo;
- TBuf8<30> driveLabel8;
- TBuf8<30> driveString8;
+ TBuf8<KDriveLabelSize> driveLabel8;
+ TBuf8<KDriveLabelSize> driveString8;
for (driveNumber=EDriveA; driveNumber<=EDriveZ; driveNumber++) {
TInt err = fs.Volume(volumeInfo, driveNumber);
if (err != KErrNone)
continue;
- if (fs.DriveToChar(driveNumber,driveLetter) != KErrNone)
+ if (fs.DriveToChar(driveNumber, driveLetter) != KErrNone)
continue;
driveLetterValue = driveLetter;
@@ -205,40 +180,46 @@ bool SymbianFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, b
sprintf(path,"%c:\\", driveNumber+'A');
SymbianFilesystemNode entry(false);
- entry._displayName = (char*)driveString8.PtrZ(); // drive_name
- entry._isDirectory = true;
- entry._isValid = true;
- entry._isPseudoRoot = false;
+ entry._displayName = (char*) driveString8.PtrZ(); // drive_name
+ entry._isDirectory = ETrue;
+ entry._isValid = ETrue;
+ entry._isPseudoRoot = EFalse;
entry._path = path;
myList.push_back(new SymbianFilesystemNode(entry));
}
} else {
- TPtrC8 ptr((const unsigned char*)_path.c_str(),_path.size());
+ TPtrC8 ptr((const unsigned char*) _path.c_str(), _path.size());
TFileName fname;
- fname.Copy(ptr);
TBuf8<256>nameBuf;
CDir* dirPtr;
- if (CEikonEnv::Static()->FsSession().GetDir(fname,KEntryAttNormal|KEntryAttDir,0,dirPtr)==KErrNone) {
+ fname.Copy(ptr);
+
+ if (_path.lastChar() != '\\')
+ fname.Append('\\');
+
+ if (static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession().GetDir(fname, KEntryAttNormal|KEntryAttDir, 0, dirPtr) == KErrNone) {
CleanupStack::PushL(dirPtr);
TInt cnt=dirPtr->Count();
for (TInt loop=0;loop<cnt;loop++) {
TEntry fileentry=(*dirPtr)[loop];
nameBuf.Copy(fileentry.iName);
- SymbianFilesystemNode entry(false);
- entry._isPseudoRoot = false;
+ SymbianFilesystemNode entry(EFalse);
+ entry._isPseudoRoot = EFalse;
- entry._displayName =(char*)nameBuf.PtrZ();
+ entry._displayName =(char*) nameBuf.PtrZ();
entry._path = _path;
- entry._path +=(char*)nameBuf.PtrZ();
+
+ if (entry._path.lastChar() != '\\')
+ entry._path+= '\\';
+
+ entry._path +=(char*) nameBuf.PtrZ();
entry._isDirectory = fileentry.IsDir();
// Honor the chosen mode
- if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) ||
- (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
+ if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) ||
+ (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory))
continue;
-
- if (entry._isDirectory)
- entry._path += "\\";
+
myList.push_back(new SymbianFilesystemNode(entry));
}
CleanupStack::PopAndDestroy(dirPtr);
@@ -254,21 +235,30 @@ AbstractFilesystemNode *SymbianFilesystemNode::getParent() const {
// Root node is its own parent. Still we can't just return this
// as the GUI code will call delete on the old node.
if (!_isPseudoRoot && _path.size() > 3) {
- p = new SymbianFilesystemNode(false);
+ p = new SymbianFilesystemNode(EFalse);
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '\\');
- p->_path = String(start, end - start);
- p->_isValid = true;
- p->_isDirectory = true;
- p->_displayName = lastPathComponent(p->_path);
+ p->_path = Common::String(start, end - start);
+ p->_isValid = ETrue;
+ p->_isDirectory = ETrue;
+ p->_displayName = lastPathComponent(p->_path, '\\');
}
else
{
- p = new SymbianFilesystemNode(true);
+ p = new SymbianFilesystemNode(ETrue);
}
return p;
}
+Common::SeekableReadStream *SymbianFilesystemNode::openForReading() {
+ return SymbianStdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *SymbianFilesystemNode::openForWriting() {
+ return SymbianStdioStream::makeFromPath(getPath().c_str(), true);
+}
#endif //#if defined (__SYMBIAN32__)
+
+
diff --git a/backends/fs/symbian/symbianstream.cpp b/backends/fs/symbian/symbianstream.cpp
new file mode 100644
index 0000000000..5944cab892
--- /dev/null
+++ b/backends/fs/symbian/symbianstream.cpp
@@ -0,0 +1,274 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+#include "backends/fs/symbian/symbianstream.h"
+#include "common/system.h"
+#include "backends/platform/symbian/src/symbianos.h"
+
+#include <f32file.h>
+
+#define KInputBufferLength 128
+
+// Symbian libc file functionality in order to provide shared file handles
+class TSymbianFileEntry {
+public:
+ RFile _fileHandle;
+ char _inputBuffer[KInputBufferLength];
+ TInt _inputBufferLen;
+ TInt _inputPos;
+ TInt _lastError;
+ TBool _eofReached;
+};
+
+TSymbianFileEntry* CreateSymbianFileEntry(const char* name, const char* mode) {
+ TSymbianFileEntry* fileEntry = new TSymbianFileEntry;
+ fileEntry->_inputPos = KErrNotFound;
+ fileEntry->_lastError = 0;
+ fileEntry->_eofReached = EFalse;
+
+ if (fileEntry != NULL) {
+ TInt modeLen = strlen(mode);
+
+ TPtrC8 namePtr((unsigned char*) name, strlen(name));
+ TFileName tempFileName;
+ tempFileName.Copy(namePtr);
+
+ TInt fileMode = EFileRead;
+
+ if (mode[0] == 'a')
+ fileMode = EFileWrite;
+
+ if (!((modeLen > 1 && mode[1] == 'b') || (modeLen > 2 && mode[2] == 'b'))) {
+ fileMode |= EFileStreamText;
+ }
+
+ if ((modeLen > 1 && mode[1] == '+') || (modeLen > 2 && mode[2] == '+')) {
+ fileMode = fileMode| EFileWrite;
+ }
+
+ fileMode = fileMode| EFileShareAny;
+
+ switch(mode[0]) {
+ case 'a':
+ if (fileEntry->_fileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) {
+ if (fileEntry->_fileHandle.Create(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) {
+ delete fileEntry;
+ fileEntry = NULL;
+ }
+ }
+ break;
+ case 'r':
+ if (fileEntry->_fileHandle.Open(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) {
+ delete fileEntry;
+ fileEntry = NULL;
+ }
+ break;
+
+ case 'w':
+ if (fileEntry->_fileHandle.Replace(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), tempFileName, fileMode) != KErrNone) {
+ delete fileEntry;
+ fileEntry = NULL;
+ }
+ break;
+ }
+ }
+ return fileEntry;
+}
+
+size_t ReadData(const void* ptr, size_t size, size_t numItems, TSymbianFileEntry* handle) {
+ TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle));
+ TUint32 totsize = size*numItems;
+ TPtr8 pointer ( (unsigned char*) ptr, totsize);
+
+ // Nothing cached and we want to load at least KInputBufferLength bytes
+ if (totsize >= KInputBufferLength) {
+ TUint32 totLength = 0;
+ if (entry->_inputPos != KErrNotFound) {
+ TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer+entry->_inputPos, entry->_inputBufferLen - entry->_inputPos, KInputBufferLength);
+ pointer.Append(cacheBuffer);
+ entry->_inputPos = KErrNotFound;
+ totLength+=pointer.Length();
+ pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength);
+ }
+
+ entry->_lastError = entry->_fileHandle.Read(pointer);
+
+ totLength+=pointer.Length();
+
+ pointer.Set((unsigned char*) ptr, totLength, totsize);
+
+ } else {
+ // Nothing in buffer
+ if (entry->_inputPos == KErrNotFound) {
+ TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer, KInputBufferLength);
+ entry->_lastError = entry->_fileHandle.Read(cacheBuffer);
+
+ if (cacheBuffer.Length() >= totsize) {
+ pointer.Copy(cacheBuffer.Left(totsize));
+ entry->_inputPos = totsize;
+ entry->_inputBufferLen = cacheBuffer.Length();
+ } else {
+ pointer.Copy(cacheBuffer);
+ entry->_inputPos = KErrNotFound;
+ }
+
+ } else {
+ TPtr8 cacheBuffer( (unsigned char*) entry->_inputBuffer, entry->_inputBufferLen, KInputBufferLength);
+
+ if (entry->_inputPos+totsize < entry->_inputBufferLen) {
+ pointer.Copy(cacheBuffer.Mid(entry->_inputPos, totsize));
+ entry->_inputPos+=totsize;
+ } else {
+
+ pointer.Copy(cacheBuffer.Mid(entry->_inputPos, entry->_inputBufferLen-entry->_inputPos));
+ cacheBuffer.SetLength(0);
+ entry->_lastError = entry->_fileHandle.Read(cacheBuffer);
+
+ if (cacheBuffer.Length() >= totsize-pointer.Length()) {
+ TUint32 restSize = totsize-pointer.Length();
+ pointer.Append(cacheBuffer.Left(restSize));
+ entry->_inputPos = restSize;
+ entry->_inputBufferLen = cacheBuffer.Length();
+ } else {
+ pointer.Append(cacheBuffer);
+ entry->_inputPos = KErrNotFound;
+ }
+ }
+ }
+ }
+
+ if((numItems * size) != pointer.Length() && entry->_lastError == KErrNone) {
+ entry->_eofReached = ETrue;
+ }
+
+ return pointer.Length() / size;
+}
+
+SymbianStdioStream::SymbianStdioStream(void *handle) : _handle(handle) {
+ assert(handle);
+}
+
+SymbianStdioStream::~SymbianStdioStream() {
+ ((TSymbianFileEntry*)(_handle))->_fileHandle.Close();
+
+ delete (TSymbianFileEntry*)(_handle);
+}
+
+bool SymbianStdioStream::err() const {
+ return ((TSymbianFileEntry*)(_handle))->_lastError != 0;
+}
+
+void SymbianStdioStream::clearErr() {
+ ((TSymbianFileEntry*)(_handle))->_lastError = 0;
+ ((TSymbianFileEntry*)(_handle))->_eofReached = 0;
+}
+
+bool SymbianStdioStream::eos() const {
+ TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle));
+
+ return entry->_eofReached != 0;
+}
+
+int32 SymbianStdioStream::pos() const {
+ TInt pos = 0;
+ TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle));
+
+ entry->_lastError = entry->_fileHandle.Seek(ESeekCurrent, pos);
+ if (entry->_lastError == KErrNone && entry->_inputPos != KErrNotFound) {
+ pos += (entry->_inputPos - entry->_inputBufferLen);
+ }
+
+ return pos;
+}
+
+int32 SymbianStdioStream::size() const {
+
+ TInt length = 0;
+ ((TSymbianFileEntry*)(_handle))->_fileHandle.Size(length);
+
+ return length;
+}
+
+bool SymbianStdioStream::seek(int32 offs, int whence) {
+ assert(_handle);
+
+ TSeek seekMode = ESeekStart;
+ TInt pos = offs;
+ TSymbianFileEntry* entry = ((TSymbianFileEntry*)(_handle));
+
+ switch (whence) {
+ case SEEK_SET:
+ seekMode = ESeekStart;
+ break;
+ case SEEK_CUR:
+ seekMode = ESeekCurrent;
+ if (entry->_inputPos != KErrNotFound) {
+ pos += (entry->_inputPos - entry->_inputBufferLen);
+ }
+ break;
+ case SEEK_END:
+ seekMode = ESeekEnd;
+ break;
+
+ }
+
+ entry->_inputPos = KErrNotFound;
+ entry->_eofReached = EFalse;
+ entry->_fileHandle.Seek(seekMode, pos);
+
+ return true; // FIXME: Probably should return a value based on what _fileHandle.Seek returns
+}
+
+uint32 SymbianStdioStream::read(void *ptr, uint32 len) {
+ return (uint32)ReadData((byte *)ptr, 1, len, (TSymbianFileEntry *)_handle);
+}
+
+uint32 SymbianStdioStream::write(const void *ptr, uint32 len) {
+ TPtrC8 pointer( (unsigned char*) ptr, len);
+
+ ((TSymbianFileEntry*)(_handle))->_inputPos = KErrNotFound;
+ ((TSymbianFileEntry*)(_handle))->_lastError = ((TSymbianFileEntry*)(_handle))->_fileHandle.Write(pointer);
+ ((TSymbianFileEntry*)(_handle))->_eofReached = EFalse;
+
+ if (((TSymbianFileEntry*)(_handle))->_lastError == KErrNone) {
+ return len;
+ }
+
+ return 0;
+}
+
+bool SymbianStdioStream::flush() {
+ ((TSymbianFileEntry*)(_handle))->_fileHandle.Flush();
+ return true;
+}
+
+SymbianStdioStream *SymbianStdioStream::makeFromPath(const Common::String &path, bool writeMode) {
+ void *handle = CreateSymbianFileEntry(path.c_str(), writeMode ? "wb" : "rb");
+ if (handle)
+ return new SymbianStdioStream(handle);
+ return 0;
+}
+
diff --git a/backends/fs/symbian/symbianstream.h b/backends/fs/symbian/symbianstream.h
new file mode 100644
index 0000000000..d783856687
--- /dev/null
+++ b/backends/fs/symbian/symbianstream.h
@@ -0,0 +1,62 @@
+/* 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 BACKENDS_FS_SYMBIANSTDIOSTREAM_H
+#define BACKENDS_FS_SYMBIANSTDIOSTREAM_H
+
+#include "common/scummsys.h"
+#include "common/noncopyable.h"
+#include "common/stream.h"
+#include "common/str.h"
+
+class SymbianStdioStream : public Common::SeekableReadStream, public Common::WriteStream, public Common::NonCopyable {
+protected:
+ /** File handle to the actual file. */
+ void *_handle;
+
+public:
+ /**
+ * Given a path, invokes fopen on that path and wrap the result in a
+ * StdioStream instance.
+ */
+ static SymbianStdioStream *makeFromPath(const Common::String &path, bool writeMode);
+
+ SymbianStdioStream(void *handle);
+ virtual ~SymbianStdioStream();
+
+ bool err() const;
+ void clearErr();
+ bool eos() const;
+
+ virtual uint32 write(const void *dataPtr, uint32 dataSize);
+ virtual bool flush();
+
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ bool seek(int32 offs, int whence = SEEK_SET);
+ uint32 read(void *dataPtr, uint32 dataSize);
+};
+
+#endif
diff --git a/backends/fs/wii/wii-fs-factory.cpp b/backends/fs/wii/wii-fs-factory.cpp
index 9839858dd5..69086a95f1 100644
--- a/backends/fs/wii/wii-fs-factory.cpp
+++ b/backends/fs/wii/wii-fs-factory.cpp
@@ -42,7 +42,7 @@ AbstractFilesystemNode *WiiFilesystemFactory::makeCurrentDirectoryFileNode() con
return new WiiFilesystemNode();
}
-AbstractFilesystemNode *WiiFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *WiiFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new WiiFilesystemNode(path, true);
}
#endif
diff --git a/backends/fs/wii/wii-fs-factory.h b/backends/fs/wii/wii-fs-factory.h
index 24badee330..36867a392c 100644
--- a/backends/fs/wii/wii-fs-factory.h
+++ b/backends/fs/wii/wii-fs-factory.h
@@ -33,11 +33,9 @@
*/
class WiiFilesystemFactory : public FilesystemFactory, public Common::Singleton<WiiFilesystemFactory> {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
protected:
WiiFilesystemFactory() {};
diff --git a/backends/fs/wii/wii-fs.cpp b/backends/fs/wii/wii-fs.cpp
index e6d0cf4c7e..a620df5471 100644
--- a/backends/fs/wii/wii-fs.cpp
+++ b/backends/fs/wii/wii-fs.cpp
@@ -23,6 +23,7 @@
#if defined(__WII__)
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#include <sys/dir.h>
@@ -37,8 +38,8 @@
*/
class WiiFilesystemNode : public AbstractFilesystemNode {
protected:
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory, _isReadable, _isWritable;
public:
@@ -50,51 +51,30 @@ public:
/**
* Creates a WiiFilesystemNode for a given path.
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
* @param verify true if the isValid and isDirectory flags should be verified during the construction.
*/
- WiiFilesystemNode(const String &path, bool verify);
+ WiiFilesystemNode(const Common::String &path, bool verify);
virtual bool exists() const;
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return _isReadable; }
virtual bool isWritable() const { return _isWritable; }
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
private:
virtual void setFlags();
};
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/') {
- --cur;
- }
-
- return cur + 1;
-}
-
void WiiFilesystemNode::setFlags() {
struct stat st;
@@ -118,12 +98,12 @@ WiiFilesystemNode::WiiFilesystemNode() {
setFlags();
}
-WiiFilesystemNode::WiiFilesystemNode(const String &p, bool verify) {
+WiiFilesystemNode::WiiFilesystemNode(const Common::String &p, bool verify) {
assert(p.size() > 0);
_path = p;
- _displayName = lastPathComponent(_path);
+ _displayName = lastPathComponent(_path, '/');
if (verify)
setFlags();
@@ -134,10 +114,10 @@ bool WiiFilesystemNode::exists() const {
return stat(_path.c_str (), &st) == 0;
}
-AbstractFilesystemNode *WiiFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *WiiFilesystemNode::getChild(const Common::String &n) const {
assert(_isDirectory);
- String newPath(_path);
+ Common::String newPath(_path);
if (newPath.lastChar() != '/')
newPath += '/';
newPath += n;
@@ -160,15 +140,15 @@ bool WiiFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
continue;
- String newPath(_path);
+ Common::String newPath(_path);
if (newPath.lastChar() != '/')
newPath += '/';
newPath += filename;
bool isDir = S_ISDIR(st.st_mode);
- if ((mode == FilesystemNode::kListFilesOnly && isDir) ||
- (mode == FilesystemNode::kListDirectoriesOnly && !isDir))
+ if ((mode == Common::FilesystemNode::kListFilesOnly && isDir) ||
+ (mode == Common::FilesystemNode::kListDirectoriesOnly && !isDir))
continue;
if (isDir)
@@ -187,9 +167,17 @@ AbstractFilesystemNode *WiiFilesystemNode::getParent() const {
return 0;
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '/');
+
+ return new WiiFilesystemNode(Common::String(start, end - start), true);
+}
+
+Common::SeekableReadStream *WiiFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
- return new WiiFilesystemNode(String(start, end - start), true);
+Common::WriteStream *WiiFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
}
#endif //#if defined(__WII__)
diff --git a/backends/fs/windows/windows-fs-factory.cpp b/backends/fs/windows/windows-fs-factory.cpp
index 7fbf4f7fff..ed273bb746 100644
--- a/backends/fs/windows/windows-fs-factory.cpp
+++ b/backends/fs/windows/windows-fs-factory.cpp
@@ -26,8 +26,6 @@
#include "backends/fs/windows/windows-fs-factory.h"
#include "backends/fs/windows/windows-fs.cpp"
-DECLARE_SINGLETON(WindowsFilesystemFactory);
-
AbstractFilesystemNode *WindowsFilesystemFactory::makeRootFileNode() const {
return new WindowsFilesystemNode();
}
@@ -36,7 +34,7 @@ AbstractFilesystemNode *WindowsFilesystemFactory::makeCurrentDirectoryFileNode()
return new WindowsFilesystemNode("", true);
}
-AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const String &path) const {
+AbstractFilesystemNode *WindowsFilesystemFactory::makeFileNodePath(const Common::String &path) const {
return new WindowsFilesystemNode(path, false);
}
#endif
diff --git a/backends/fs/windows/windows-fs-factory.h b/backends/fs/windows/windows-fs-factory.h
index 0745b286a8..3c7b80942d 100644
--- a/backends/fs/windows/windows-fs-factory.h
+++ b/backends/fs/windows/windows-fs-factory.h
@@ -25,7 +25,6 @@
#ifndef WINDOWS_FILESYSTEM_FACTORY_H
#define WINDOWS_FILESYSTEM_FACTORY_H
-#include "common/singleton.h"
#include "backends/fs/fs-factory.h"
/**
@@ -33,19 +32,11 @@
*
* Parts of this class are documented in the base interface class, FilesystemFactory.
*/
-class WindowsFilesystemFactory : public FilesystemFactory, public Common::Singleton<WindowsFilesystemFactory> {
+class WindowsFilesystemFactory : public FilesystemFactory {
public:
- typedef Common::String String;
-
virtual AbstractFilesystemNode *makeRootFileNode() const;
virtual AbstractFilesystemNode *makeCurrentDirectoryFileNode() const;
- virtual AbstractFilesystemNode *makeFileNodePath(const String &path) const;
-
-protected:
- WindowsFilesystemFactory() {};
-
-private:
- friend class Common::Singleton<SingletonBaseType>;
+ virtual AbstractFilesystemNode *makeFileNodePath(const Common::String &path) const;
};
#endif /*WINDOWS_FILESYSTEM_FACTORY_H*/
diff --git a/backends/fs/windows/windows-fs.cpp b/backends/fs/windows/windows-fs.cpp
index ac2f521e21..c59c7dbe71 100644
--- a/backends/fs/windows/windows-fs.cpp
+++ b/backends/fs/windows/windows-fs.cpp
@@ -24,24 +24,17 @@
#ifdef WIN32
-#ifdef ARRAYSIZE
-#undef ARRAYSIZE
-#endif
-#ifdef _WIN32_WCE
#include <windows.h>
// winnt.h defines ARRAYSIZE, but we want our own one...
#undef ARRAYSIZE
+#ifdef _WIN32_WCE
#undef GetCurrentDirectory
#endif
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
-#ifndef _WIN32_WCE
-#include <windows.h>
-// winnt.h defines ARRAYSIZE, but we want our own one...
-#undef ARRAYSIZE
-#endif
#include <tchar.h>
// F_OK, R_OK and W_OK are not defined under MSVC, so we define them here
@@ -66,8 +59,8 @@
*/
class WindowsFilesystemNode : public AbstractFilesystemNode {
protected:
- String _displayName;
- String _path;
+ Common::String _displayName;
+ Common::String _path;
bool _isDirectory;
bool _isPseudoRoot;
bool _isValid;
@@ -89,23 +82,26 @@ public:
* path=c:\foo\bar.txt, currentDir=true -> current directory
* path=NULL, currentDir=true -> current directory
*
- * @param path String with the path the new node should point to.
+ * @param path Common::String with the path the new node should point to.
* @param currentDir if true, the path parameter will be ignored and the resulting node will point to the current directory.
*/
- WindowsFilesystemNode(const String &path, const bool currentDir);
+ WindowsFilesystemNode(const Common::String &path, const bool currentDir);
virtual bool exists() const { return _access(_path.c_str(), F_OK) == 0; }
- virtual String getDisplayName() const { return _displayName; }
- virtual String getName() const { return _displayName; }
- virtual String getPath() const { return _path; }
+ virtual Common::String getDisplayName() const { return _displayName; }
+ virtual Common::String getName() const { return _displayName; }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return _isDirectory; }
virtual bool isReadable() const { return _access(_path.c_str(), R_OK) == 0; }
virtual bool isWritable() const { return _access(_path.c_str(), W_OK) == 0; }
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting();
+
private:
/**
* Adds a single WindowsFilesystemNode to a given list.
@@ -113,7 +109,7 @@ private:
*
* @param list List to put the file entry node in.
* @param mode Mode to use while adding the file entry to the list.
- * @param base String with the directory being listed.
+ * @param base Common::String with the directory being listed.
* @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find.
*/
static void addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data);
@@ -121,7 +117,7 @@ private:
/**
* Converts a Unicode string to Ascii format.
*
- * @param str String to convert from Unicode to Ascii.
+ * @param str Common::String to convert from Unicode to Ascii.
* @return str in Ascii format.
*/
static char *toAscii(TCHAR *str);
@@ -129,36 +125,12 @@ private:
/**
* Converts an Ascii string to Unicode format.
*
- * @param str String to convert from Ascii to Unicode.
+ * @param str Common::String to convert from Ascii to Unicode.
* @return str in Unicode format.
*/
static const TCHAR* toUnicode(const char *str);
};
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * c:\foo\bar.txt would return "\bar.txt"
- * c:\foo\bar\ would return "\bar\"
- *
- * @param str Path to obtain the last component from.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '\\') {
- --cur;
- }
-
- return cur + 1;
-}
-
void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, WIN32_FIND_DATA* find_data) {
WindowsFilesystemNode entry;
char *asciiName = toAscii(find_data->cFileName);
@@ -170,8 +142,8 @@ void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const c
isDirectory = (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? true : false);
- if ((!isDirectory && mode == FilesystemNode::kListDirectoriesOnly) ||
- (isDirectory && mode == FilesystemNode::kListFilesOnly))
+ if ((!isDirectory && mode == Common::FilesystemNode::kListDirectoriesOnly) ||
+ (isDirectory && mode == Common::FilesystemNode::kListFilesOnly))
return;
entry._isDirectory = isDirectory;
@@ -222,18 +194,17 @@ WindowsFilesystemNode::WindowsFilesystemNode() {
#endif
}
-WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool currentDir) {
+WindowsFilesystemNode::WindowsFilesystemNode(const Common::String &p, const bool currentDir) {
if (currentDir) {
char path[MAX_PATH];
GetCurrentDirectory(MAX_PATH, path);
_path = path;
- }
- else {
+ } else {
assert(p.size() > 0);
_path = p;
}
- _displayName = lastPathComponent(_path);
+ _displayName = lastPathComponent(_path, '\\');
// Check whether it is a directory, and whether the file actually exists
DWORD fileAttribs = GetFileAttributes(toUnicode(_path.c_str()));
@@ -252,19 +223,14 @@ WindowsFilesystemNode::WindowsFilesystemNode(const String &p, const bool current
_isPseudoRoot = false;
}
-AbstractFilesystemNode *WindowsFilesystemNode::getChild(const String &n) const {
+AbstractFilesystemNode *WindowsFilesystemNode::getChild(const Common::String &n) const {
assert(_isDirectory);
- String newPath(_path);
+ Common::String newPath(_path);
if (_path.lastChar() != '\\')
newPath += '\\';
newPath += n;
- // Check whether the directory actually exists
- DWORD fileAttribs = GetFileAttributes(toUnicode(newPath.c_str()));
- if (fileAttribs == INVALID_FILE_ATTRIBUTES)
- return 0;
-
return new WindowsFilesystemNode(newPath, false);
}
@@ -328,17 +294,25 @@ AbstractFilesystemNode *WindowsFilesystemNode::getParent() const {
WindowsFilesystemNode *p = new WindowsFilesystemNode();
if (_path.size() > 3) {
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '\\');
p = new WindowsFilesystemNode();
- p->_path = String(start, end - start);
+ p->_path = Common::String(start, end - start);
p->_isValid = true;
p->_isDirectory = true;
- p->_displayName = lastPathComponent(p->_path);
+ p->_displayName = lastPathComponent(p->_path, '\\');
p->_isPseudoRoot = false;
}
return p;
}
+Common::SeekableReadStream *WindowsFilesystemNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
+}
+
+Common::WriteStream *WindowsFilesystemNode::openForWriting() {
+ return StdioStream::makeFromPath(getPath().c_str(), true);
+}
+
#endif //#ifdef WIN32
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 2a252b9323..5a978a0fd2 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -79,20 +79,18 @@ MidiDriver_ALSA::MidiDriver_ALSA()
}
int MidiDriver_ALSA::open() {
- const char *var;
+ const char *var = NULL;
if (_isOpen)
return MERR_ALREADY_OPEN;
_isOpen = true;
- if (!(var = getenv("SCUMMVM_PORT"))) {
- // use config option if no var specified
+ var = getenv("SCUMMVM_PORT");
+ if (!var && ConfMan.hasKey("alsa_port")) {
var = ConfMan.get("alsa_port").c_str();
- if (parse_addr(var, &seq_client, &seq_port) < 0) {
- error("Invalid port %s", var);
- return -1;
- }
- } else {
+ }
+
+ if (var) {
if (parse_addr(var, &seq_client, &seq_port) < 0) {
error("Invalid port %s", var);
return -1;
@@ -120,14 +118,32 @@ int MidiDriver_ALSA::open() {
return -1;
}
- if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
- /* subscribe to MIDI port */
- if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
- error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
+ if (var) {
+ if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
+ // subscribe to MIDI port
+ if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
+ error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
+ }
}
- else printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port);
+ } else {
+ int defaultPorts[] = {
+ 65, 0,
+ 17, 0
+ };
+ int i;
+
+ for (i = 0; i < ARRAYSIZE(defaultPorts); i += 2) {
+ seq_client = defaultPorts[i];
+ seq_port = defaultPorts[i + 1];
+ if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) >= 0)
+ break;
+ }
+
+ if (i >= ARRAYSIZE(defaultPorts))
+ error("Can't subscribe to MIDI port (65:0) or (17:0)");
}
+ printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port);
printf("ALSA client initialised [%d:0]\n", my_client);
return 0;
diff --git a/backends/midi/seq.cpp b/backends/midi/seq.cpp
index 57a5a1ea32..9e86181674 100644
--- a/backends/midi/seq.cpp
+++ b/backends/midi/seq.cpp
@@ -28,7 +28,7 @@
* both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html)
*/
-#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__)
+#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__)
#include "common/util.h"
#include "sound/musicplugin.h"
diff --git a/backends/midi/stmidi.cpp b/backends/midi/stmidi.cpp
new file mode 100644
index 0000000000..addb23c6bd
--- /dev/null
+++ b/backends/midi/stmidi.cpp
@@ -0,0 +1,155 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * 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.
+ */
+
+/*
+ * Raw MIDI output for the Atari ST line of computers.
+ * Based on the ScummVM SEQ & CoreMIDI drivers.
+ * Atari code by Keith Scroggins
+ * We, unfortunately, could not use the SEQ driver because the /dev/midi under
+ * FreeMiNT (and hence in libc) is considered to be a serial port for machine
+ * access. So, we just use OS calls then to send the data to the MIDI ports
+ * directly. The current implementation is sending 1 byte at a time because
+ * in most cases we are only sending up to 3 bytes, I believe this saves a few
+ * cycles. I might change so sysex messages are sent the other way later.
+ */
+
+#if defined __MINT__
+
+#include <osbind.h>
+#include "sound/mpu401.h"
+#include "common/util.h"
+#include "sound/musicplugin.h"
+
+class MidiDriver_STMIDI : public MidiDriver_MPU401 {
+public:
+ MidiDriver_STMIDI() : _isOpen (false) { }
+ int open();
+ void close();
+ void send(uint32 b);
+ void sysEx(const byte *msg, uint16 length);
+
+private:
+ bool _isOpen;
+};
+
+int MidiDriver_STMIDI::open() {
+ if ((_isOpen) && (!Bcostat(4)))
+ return MERR_ALREADY_OPEN;
+ warning("ST Midi Port Open");
+ _isOpen = true;
+ return 0;
+}
+
+void MidiDriver_STMIDI::close() {
+ MidiDriver_MPU401::close();
+ _isOpen = false;
+}
+
+void MidiDriver_STMIDI::send(uint32 b) {
+
+ byte status_byte = (b & 0x000000FF);
+ byte first_byte = (b & 0x0000FF00) >> 8;
+ byte second_byte = (b & 0x00FF0000) >> 16;
+
+// warning("ST MIDI Packet sent");
+
+ switch (b & 0xF0) {
+ case 0x80: // Note Off
+ case 0x90: // Note On
+ case 0xA0: // Polyphonic Key Pressure
+ case 0xB0: // Controller
+ case 0xE0: // Pitch Bend
+ Bconout(3, status_byte);
+ Bconout(3, first_byte);
+ Bconout(3, second_byte);
+ break;
+ case 0xC0: // Program Change
+ case 0xD0: // Aftertouch
+ Bconout(3, status_byte);
+ Bconout(3, first_byte);
+ break;
+ default:
+ fprintf(stderr, "Unknown : %08x\n", (int)b);
+ break;
+ }
+}
+
+void MidiDriver_STMIDI::sysEx (const byte *msg, uint16 length) {
+ if (length > 254) {
+ warning ("Cannot send SysEx block - data too large");
+ return;
+ }
+
+ const byte *chr = msg;
+ warning("Sending SysEx Message");
+
+ Bconout(3, '0xF0');
+ for (; length; --length, ++chr) {
+ Bconout(3,((unsigned char) *chr & 0x7F));
+ }
+ Bconout(3, '0xF7');
+}
+
+// Plugin interface
+
+class StMidiMusicPlugin : public MusicPluginObject {
+public:
+ const char *getName() const {
+ return "STMIDI";
+ }
+
+ const char *getId() const {
+ return "stmidi";
+ }
+
+ MusicDevices getDevices() const;
+ PluginError createInstance(Audio::Mixer *mixer, MidiDriver **mididriver)
+ const;
+};
+
+MusicDevices StMidiMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ // TODO: Return a different music type depending on the configuration
+ // TODO: List the available devices
+ devices.push_back(MusicDevice(this, "", MT_GM));
+ return devices;
+}
+
+PluginError StMidiMusicPlugin::createInstance(Audio::Mixer *mixer, MidiDriver **mididriver) const {
+ *mididriver = new MidiDriver_STMIDI();
+
+ return kNoError;
+}
+
+MidiDriver *MidiDriver_STMIDI_create(Audio::Mixer *mixer) {
+ MidiDriver *mididriver;
+
+ StMidiMusicPlugin p;
+ p.createInstance(mixer, &mididriver);
+
+ return mididriver;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(STMIDI)
+ //REGISTER_PLUGIN_DYNAMIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin);
+//#else
+ REGISTER_PLUGIN_STATIC(STMIDI, PLUGIN_TYPE_MUSIC, StMidiMusicPlugin);
+//#endif
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index cd4fe5407c..ba4cefc3c0 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -1,6 +1,8 @@
MODULE := backends
MODULE_OBJS := \
+ fs/abstract-fs.o \
+ fs/stdiostream.o \
fs/amigaos4/amigaos4-fs-factory.o \
fs/ds/ds-fs-factory.o \
fs/palmos/palmos-fs-factory.o \
@@ -17,6 +19,7 @@ MODULE_OBJS := \
midi/coremidi.o \
midi/quicktime.o \
midi/seq.o \
+ midi/stmidi.o \
midi/timidity.o \
midi/dmedia.o \
midi/windows.o \
diff --git a/backends/platform/PalmOS/Src/be_base.cpp b/backends/platform/PalmOS/Src/be_base.cpp
index afb3f15bae..32e68bde9f 100644
--- a/backends/platform/PalmOS/Src/be_base.cpp
+++ b/backends/platform/PalmOS/Src/be_base.cpp
@@ -30,6 +30,9 @@
#include "backends/timer/default/default-timer.h"
#include "sound/mixer.h"
+#define DEFAULT_SAVE_PATH "/PALM/Programs/ScummVM/Saved"
+
+
OSystem_PalmBase::OSystem_PalmBase() {
_overlayVisible = false;
@@ -100,7 +103,7 @@ void OSystem_PalmBase::initBackend() {
// Create the savefile manager, if none exists yet (we check for this to
// allow subclasses to provide their own).
if (_saveMgr == 0) {
- _saveMgr = new DefaultSaveFileManager();
+ _saveMgr = new DefaultSaveFileManager(DEFAULT_SAVE_PATH);
}
// Create and hook up the mixer, if none exists yet (we check for this to
diff --git a/backends/platform/dc/dc-fs.cpp b/backends/platform/dc/dc-fs.cpp
index f4dc4037df..4baba5b7dc 100644
--- a/backends/platform/dc/dc-fs.cpp
+++ b/backends/platform/dc/dc-fs.cpp
@@ -24,6 +24,7 @@
#include "dc.h"
#include "backends/fs/abstract-fs.h"
+#include "backends/fs/stdiostream.h"
#include <ronin/cdfs.h>
#include <stdio.h>
@@ -34,75 +35,52 @@
*
* Parts of this class are documented in the base interface class, AbstractFilesystemNode.
*/
-
-/* A file */
class RoninCDFileNode : public AbstractFilesystemNode {
protected:
- String _path;
- static const char *lastPathComponent(const Common::String &str);
+ Common::String _path;
public:
- RoninCDFileNode(const String &path) : _path(path) {};
+ RoninCDFileNode(const Common::String &path) : _path(path) {};
virtual bool exists() const { return true; }
- virtual String getName() const { return lastPathComponent(_path); }
- virtual String getPath() const { return _path; }
+ virtual Common::String getName() const { return lastPathComponent(_path, '/'); }
+ virtual Common::String getPath() const { return _path; }
virtual bool isDirectory() const { return false; }
virtual bool isReadable() const { return true; }
virtual bool isWritable() const { return false; }
- virtual AbstractFilesystemNode *getChild(const String &n) const { return NULL; }
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const { return NULL; }
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const { return false; }
virtual AbstractFilesystemNode *getParent() const;
+ virtual Common::SeekableReadStream *openForReading();
+ virtual Common::WriteStream *openForWriting() { return 0; }
+
static AbstractFilesystemNode *makeFileNodePath(const Common::String &path);
};
/* A directory */
class RoninCDDirectoryNode : public RoninCDFileNode {
public:
- RoninCDDirectoryNode(const String &path) : RoninCDFileNode(path) {};
+ RoninCDDirectoryNode(const Common::String &path) : RoninCDFileNode(path) {};
virtual bool isDirectory() const { return true; }
- virtual AbstractFilesystemNode *getChild(const String &n) const;
+ virtual AbstractFilesystemNode *getChild(const Common::String &n) const;
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
+ virtual Common::SeekableReadStream *openForReading() { return 0; }
};
/* A file/directory which does not exist */
class RoninCDNonexistingNode : public RoninCDFileNode {
public:
- RoninCDNonexistingNode(const String &path) : RoninCDFileNode(path) {};
+ RoninCDNonexistingNode(const Common::String &path) : RoninCDFileNode(path) {};
virtual bool exists() const { return false; }
virtual bool isReadable() const { return false; }
+ virtual Common::SeekableReadStream *openForReading() { return 0; }
};
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return /bar.txt
- * /foo/bar/ would return /bar/
- *
- * @param str String containing the path.
- * @return Pointer to the first char of the last component inside str.
- */
-const char *RoninCDFileNode::lastPathComponent(const Common::String &str) {
- if(str.empty())
- return "";
-
- const char *start = str.c_str();
- const char *cur = start + str.size() - 2;
-
- while (cur >= start && *cur != '/') {
- --cur;
- }
-
- return cur + 1;
-}
-
-AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path)
-{
+AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &path) {
assert(path.size() > 0);
int fd;
@@ -110,18 +88,16 @@ AbstractFilesystemNode *RoninCDFileNode::makeFileNodePath(const Common::String &
if ((fd = open(path.c_str(), O_RDONLY)) >= 0) {
close(fd);
return new RoninCDFileNode(path);
- }
- else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) {
+ } else if ((fd = open(path.c_str(), O_DIR|O_RDONLY)) >= 0) {
close(fd);
return new RoninCDDirectoryNode(path);
- }
- else {
+ } else {
return NULL;
}
}
-AbstractFilesystemNode *RoninCDDirectoryNode::getChild(const String &n) const {
- String newPath(_path);
+AbstractFilesystemNode *RoninCDDirectoryNode::getChild(const Common::String &n) const {
+ Common::String newPath(_path);
if (_path.lastChar() != '/')
newPath += '/';
newPath += n;
@@ -139,20 +115,20 @@ bool RoninCDDirectoryNode::getChildren(AbstractFSList &myList, ListMode mode, bo
// ... loop over dir entries using readdir
while ((dp = readdir(dirp)) != NULL) {
- String newPath(_path);
+ Common::String newPath(_path);
if (newPath.lastChar() != '/')
newPath += '/';
newPath += dp->d_name;
if (dp->d_size < 0) {
// Honor the chosen mode
- if (mode == FilesystemNode::kListFilesOnly)
+ if (mode == Common::FilesystemNode::kListFilesOnly)
continue;
myList.push_back(new RoninCDDirectoryNode(newPath+"/"));
} else {
// Honor the chosen mode
- if (mode == FilesystemNode::kListDirectoriesOnly)
+ if (mode == Common::FilesystemNode::kListDirectoriesOnly)
continue;
myList.push_back(new RoninCDFileNode(newPath));
@@ -168,9 +144,14 @@ AbstractFilesystemNode *RoninCDFileNode::getParent() const {
return 0;
const char *start = _path.c_str();
- const char *end = lastPathComponent(_path);
+ const char *end = lastPathComponent(_path, '/');
+
+ return new RoninCDDirectoryNode(Common::String(start, end - start));
+}
+
- return new RoninCDDirectoryNode(String(start, end - start));
+Common::SeekableReadStream *RoninCDFileNode::openForReading() {
+ return StdioStream::makeFromPath(getPath().c_str(), false);
}
AbstractFilesystemNode *OSystem_Dreamcast::makeRootFileNode() const {
diff --git a/backends/platform/dc/selector.cpp b/backends/platform/dc/selector.cpp
index 91c851506f..883787781a 100644
--- a/backends/platform/dc/selector.cpp
+++ b/backends/platform/dc/selector.cpp
@@ -26,8 +26,8 @@
#include <common/scummsys.h>
#include <engines/engine.h>
#include <engines/metaengine.h>
+#include <engines/game.h>
#include <base/plugins.h>
-#include <base/game.h>
#include <common/fs.h>
#include <common/events.h>
#include "dc.h"
@@ -146,12 +146,12 @@ struct Dir
{
char name[252];
char deficon[256];
- FilesystemNode node;
+ Common::FilesystemNode node;
};
static Game the_game;
-static bool isIcon(const FilesystemNode &entry)
+static bool isIcon(const Common::FilesystemNode &entry)
{
int l = entry.getDisplayName().size();
if (l>4 && !strcasecmp(entry.getDisplayName().c_str()+l-4, ".ICO"))
@@ -198,14 +198,14 @@ static int findGames(Game *games, int max)
{
Dir *dirs = new Dir[MAX_DIR];
int curr_game = 0, curr_dir = 0, num_dirs = 1;
- dirs[0].node = FilesystemNode("");
+ dirs[0].node = Common::FilesystemNode("");
while (curr_game < max && curr_dir < num_dirs) {
strncpy(dirs[curr_dir].name, dirs[curr_dir].node.getPath().c_str(), 252);
dirs[curr_dir].name[251] = '\0';
dirs[curr_dir].deficon[0] = '\0';
- FSList files, fslist;
- dirs[curr_dir++].node.getChildren(fslist, FilesystemNode::kListAll);
- for (FSList::const_iterator entry = fslist.begin(); entry != fslist.end();
+ Common::FSList files, fslist;
+ dirs[curr_dir++].node.getChildren(fslist, Common::FilesystemNode::kListAll);
+ for (Common::FSList::const_iterator entry = fslist.begin(); entry != fslist.end();
++entry) {
if (entry->isDirectory()) {
if (num_dirs < MAX_DIR && strcasecmp(entry->getDisplayName().c_str(),
diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp
index 6ab8fc4558..d17e1f6213 100644
--- a/backends/platform/dc/vmsave.cpp
+++ b/backends/platform/dc/vmsave.cpp
@@ -269,14 +269,15 @@ class InVMSave : public Common::InSaveFile {
private:
char *buffer;
int _pos, _size;
+ bool _eos;
uint32 read(void *buf, uint32 cnt);
- void skip(uint32 offset);
- void seek(int32 offs, int whence);
+ bool skip(uint32 offset);
+ bool seek(int32 offs, int whence);
public:
InVMSave()
- : _pos(0), buffer(NULL)
+ : _pos(0), buffer(NULL), _eos(false)
{ }
~InVMSave()
@@ -285,9 +286,10 @@ public:
delete[] buffer;
}
- bool eos() const { return _pos >= _size; }
- uint32 pos() const { return _pos; }
- uint32 size() const { return _size; }
+ bool eos() const { return _eos; }
+ void clearErr() { _eos = false; }
+ int32 pos() const { return _pos; }
+ int32 size() const { return _size; }
bool readSaveGame(const char *filename)
{ return ::readSaveGame(buffer, _size, filename); }
@@ -312,8 +314,8 @@ public:
~OutVMSave();
- bool ioFailed() const { return iofailed; }
- void clearIOFailed() { iofailed = false; }
+ bool err() const { return iofailed; }
+ void clearErr() { iofailed = false; }
void finalize();
};
@@ -370,6 +372,7 @@ uint32 InVMSave::read(void *buf, uint32 cnt)
int nbyt = cnt;
if (_pos + nbyt > _size) {
cnt = (_size - _pos);
+ _eos = true;
nbyt = cnt;
}
if (nbyt)
@@ -378,15 +381,16 @@ uint32 InVMSave::read(void *buf, uint32 cnt)
return cnt;
}
-void InVMSave::skip(uint32 offset)
+bool InVMSave::skip(uint32 offset)
{
int nbyt = offset;
if (_pos + nbyt > _size)
nbyt = (_size - _pos);
_pos += nbyt;
+ return true;
}
-void InVMSave::seek(int32 offs, int whence)
+bool InVMSave::seek(int32 offs, int whence)
{
switch(whence) {
case SEEK_SET:
@@ -403,6 +407,8 @@ void InVMSave::seek(int32 offs, int whence)
_pos = 0;
else if (_pos > _size)
_pos = _size;
+ _eos = false;
+ return true;
}
uint32 OutVMSave::write(const void *buf, uint32 cnt)
diff --git a/backends/platform/ds/arm7/Makefile b/backends/platform/ds/arm7/Makefile
index 55db7f8cad..82637845db 100644
--- a/backends/platform/ds/arm7/Makefile
+++ b/backends/platform/ds/arm7/Makefile
@@ -107,7 +107,7 @@ MAPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.map)))
export OFILES := $(MAPFILES:.map=.o) $(RAWFILES:.raw=.o) $(PALFILES:.pal=.o) $(BINFILES:.bin=.o) $(PCXFILES:.pcx=.o)\
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
-export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -I- -I$(CURDIR)/../commoninclude\
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) -Iquote -I$(CURDIR)/../commoninclude\
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include/nds)\
-I$(CURDIR)/$(BUILD) -I$(CURDIR)/source/libcartreset
diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp
index bee39f1efe..d252ed44de 100644
--- a/backends/platform/ds/arm7/source/main.cpp
+++ b/backends/platform/ds/arm7/source/main.cpp
@@ -233,7 +233,7 @@ void DummyHandler() {
REG_IF = REG_IF;
}
-uint16 powerManagerWrite(uint32 command, u32 data, bool enable) {
+void powerManagerWrite(uint32 command, u32 data, bool enable) {
uint16 result;
SerialWaitBusy();
@@ -261,9 +261,6 @@ uint16 powerManagerWrite(uint32 command, u32 data, bool enable) {
REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz;
REG_SPIDATA = enable? (result | data): (result & ~data);
SerialWaitBusy();
-
- // FIXME: This function should either return something, or have a comment
- // explaining why it is valid for it to not return something. :-)
}
/*
diff --git a/backends/platform/ds/arm9/dist/readme_ds.txt b/backends/platform/ds/arm9/dist/readme_ds.txt
new file mode 100644
index 0000000000..f77da418c9
--- /dev/null
+++ b/backends/platform/ds/arm9/dist/readme_ds.txt
@@ -0,0 +1,840 @@
+
+
+
+ The official port of ScummVM
+ to the Nintendo DS handheld console
+ by Neil Millstone (agentq)
+ http://scummvm.drunkencoders.com
+------------------------------------------------------------------------
+Visit the main ScummVM website <http://www.scummvm.org>
+
+
+
+
+ Contents
+ ------------------------------------------------------------------------
+
+
+
+ * What's New?
+ * What is ScummVM DS?
+ * Features
+ * Screenshots
+ * How to Get ScummVM DS Onto Your DS - Simple Explanation
+ o Using a CF/SD/Mini SD/Micro SD card reader and a DLDI driver
+ o Instructions for specific card readers
+ * What to do if saving doesn't work or your card gets corruped -
+ force SRAM saves
+ * How to use ScummVM DS
+ * Game Specific Controls
+ * DS Options Screen
+ * Which games are compatible with ScummVM DS
+ * Predictive dictionary for Sierra AGI games
+ * Converting your CD audio
+ * Converting speech to MP3 format
+ * Frequently Asked Questions
+ * Downloads
+ * Contributors
+ * Donations and Getting Help
+ * Building from Sources
+
+
+
+ What's New?
+ ------------------------------------------------------------------------
+
+ScummVM DS 0.12.0
+
+ * New games supported: Lure of the Temptress, Nippon Safes, Lost in Time.
+ * New laptop-style trackpad input method. Uses relative movement when you
+ drag on the touch screen.
+ * New option which allows you to drag to hover, tap the touch screen to
+ click, and double tap the screen to right click.
+ * Reorganised DS Options screen into three tabs for clearer navigation
+ * New top screen scaling options let you choose the scaling factor used
+ on startup.
+ * The usual round of bug fixes.
+
+
+ScummVM DS 0.11.1
+
+ * Bugfix release - No new DS port features
+
+
+ScummVM DS 0.11.0
+
+ * New games supported: Elvira 1 and 2, Waxworks (Amiga version)
+ * Software scaler for improved image quality. Turn it on using the DS options
+ screen (press select during the game). Thanks to Tramboi and Robin Watts for
+ this feature!
+ * Function keys added to virtual keyboard (used in AGI games)
+ * Plenty of bug fixes
+
+ What is ScummVM DS?
+ ------------------------------------------------------------------------
+
+ScummVM DS is a part of the ScummVM project. The ScummVM project is an
+attempt to re-engineer many classic point and click adventure games of the
+80s and 90s to run on modern computer hardware. Technology has changed a
+lot since these games were written, and so ScummVM attempts to replicate the
+gameplay of the original games in exacting details, without any of the original
+code that the game ran on. ScummVM needs a copy of the original game, in order
+to take the graphics, sound, and scripts that made the game work.
+
+ScummVM is written in such a way that it can be 'ported' from one type of
+machine to another, and ScummVM DS is a port of ScummVM to the Nintendo DS
+handheld games console.
+
+
+ Features
+ ------------------------------------------------------------------------
+
+ * Runs nearly all of Lucasarts' SCUMM games up to and including Sam
+ & Max Hit the Road
+ * Runs many non-Lucasarts point-and-click adventures too
+ * Supports sound
+ * Provides a GUI to change settings and choose games
+ * Supports using the DS touch screen for controls
+ * Suports saving games to compatible flash cards
+ * All games run at pretty much full speed
+
+
+
+
+
+ How to Get ScummVM DS Onto Your DS - Simple Explanation
+ ------------------------------------------------------------------------
+
+Nintendo don't want you to run ScummVM on your DS. They control
+which companies can make games on the DS, and there is an expensive
+process to go through in order to be licenced. Having to pay for
+this would prevent me from giving away ScummVM for free.
+
+So, the result is that to run ScummVM on your DS you'll need an
+unofficial card reader. There are many of these, and all are different.
+Popular models at the time of writing are the R4DS and the M3DS Real,
+but many different models work. You need to buy one of these, and at
+MicroSD card to go with it.
+
+There are also slot-2 card readers which fit into the bottom slot on
+your DS, usually used for Game Boy Advance games. These are less common
+these days, and although they have certain advantages, the details of
+these are beyond the scope of this website. Information on these is
+quite easy to find by searching.
+
+Once you have your card reader and a MicroSD card, you will also need
+a copy of the game you want to run. ScummVM can run a large variety
+of games, but you must own a real boxed copy of the game. These games
+are still under copyright, and it is illegal to copy them from a friend
+or download them from the Internet without paying. The exception to
+this are the three Revolution Software games. These are 'Beneath a
+Steel Sky', 'Lure of the Temptress' and 'Flight of the Amazon Queen'.
+Revolution have kindly allowed us to give these games away for free.
+You can download them from the main ScummVM site at
+<http://www.scummvm.org/downloads.php>
+
+NOTE: Previous version of ScummVM DS supported a method which used a
+zip file to run games on unsupported flash card readers. This method
+is no longer supported.
+
+
+ How to Get ScummVM DS Onto Your DS - Using a CF/SD/Mini SD/Micro
+ SD card reader and a DLDI driver
+ ------------------------------------------------------------------------
+
+ScummVM DS needs something called a DLDI driver to run on each make
+and model of card reader. Many modern card readers (R4DS, M3 DS Real)
+handle this autmatically and for those, you don't have to do anything.
+Just running ScummVM on the card will handle this step for you.
+For others, you will need to follow the steps in this section before
+ScummVM DS will work.
+
+All DS card readers are different in the way that they work. In order to
+support many different card readers, ScummVM DS uses a DLDI driver installed
+into the ScummVM DS code. This is done using a program called DLDITool
+which you can download and run on your computer. Each DLDI driver is
+designed to tell ScummVM DS how to use a specific type of card reader.
+These drivers can be used with any homebrew program which supports the
+DLDI interface.
+
+While each card reader should work with these instructions, there are
+some exceptions. Please read the card reader notes
+section to see if there is any specific information about your card reader.
+
+Here is what you need to do:
+
+ * Visit the DLDI page <http://dldi.drunkencoders.com/> and
+ download the executable for DLDITool for your operating system
+ (versions are available for Windows, Linux, and MacOS)
+ * Download the DLDI for your card reader. This is the big table at
+ the top of the page. The first column marked DLDI is the one you
+ want. You should get a single file with a .dldi extension.
+ * Extract DLDITool into a folder, and put the DLDI of your choice in
+ the same folder.
+ * If you're using the command line version of DLDITool enter the
+ following at a command prompt:
+
+ dlditool <dldiname> <scummvm nds name>
+
+
+ If you're using the Windows GUI version, double click on
+ dlditool32.exe, select your card reader from the box, drag your
+ ScummVM binaries (either the .nds, or the .ds.gba version
+ depending on your card reader. I think only Supercards use the
+ .ds.gba files) into the lower box, then click patch.
+
+ Either way, you should see 'Patched Successfully'. If you don't,
+ you're doing something wrong.
+
+ You need to patch one of the builds labeled A - F depending on
+ which game you want to run. See the table on the ScummVM DS
+ website to see which games are supported by which build.
+
+ * Put the patched .nds or .ds.gba files on your flash card. If
+ you're using the Supercard, you will need to use the .ds.gba
+ files, but rename them to .nds.
+ * Put your game data in any folder on the card. Do NOT use a zip file.
+ * Boot up your DS and run ScummVM.
+ * Click 'Add Game', browse to the folder with your game data, click
+ 'Choose', then 'OK'. Click 'Start' to run the game.
+
+If your copy of ScummVM DS has been successfully patched, you will get a
+message on the top screen that looks like this:
+
+ DLDI Device:
+ GBA Movie Player (Compact Flash)
+
+The message should show the name of your card reader. If it is wrong,
+you have used the wrong DLDI file.
+
+If you haven't patched your .nds file, you will get the following message
+
+ DLDI Driver not patched!
+ DLDI Initialise failed.
+
+In this case, you've made a mistake following the above instructions, or
+have patched the wrong file.
+
+You may also see the following message:
+
+ DLDI Device:
+ GBA Movie Player (Compact Flash)
+ DLDI Initialise failed.
+
+In this case, the driver did not start up correctly. The driver is
+probably broken, or you've used the wrong one for your card reader.
+
+In the case of the Supercard, M3 Lite and DS Link, there are several
+drivers available. You might want to try one of the others.
+
+This version of ScummVM DS will run on any card reader that has a DLDI
+driver available. If yours doesn't, you need to pressure your card
+reader manufacturer to release one.
+
+DO NOT EMAIL ME TO ASK ME TO CREATE A DRIVER FOR YOUR CARD READER, I
+CANNOT DO THIS.
+
+
+ How to Get ScummVM DS Onto Your DS - Instructions for specific
+ card readers
+ ------------------------------------------------------------------------
+
+ * *GBAMP CF:* You need to upload replacement firmware to your card
+ reader before it will work. You can download the firmware program
+ here <http://chishm.drunkencoders.com/NDSMP/index.html>. Name your
+ .nds file _BOOT_MP.nds.
+ * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game
+ Manager in order to avoid an annoying message when you boot your
+ M3. Use the default options to copy the file. Be sure to press 'A'
+ in the M3 browser to start the .nds file, and not 'Start', or it
+ won't work.
+ * *M3 CF/SD:* Copy the .nds file to your card with the M3 Game
+ Manager in order to avoid an annoying message when you boot your
+ M3. Use the default options to copy the file. Be sure to press 'A'
+ in the M3 browser to start the .nds file, and not 'Start', or it
+ won't work.
+ * *Supercard CF/SD (slot-2):* Use the .ds.gba files to run ScummVM
+ on the Supercard. Other than that, just follow the instructions as
+ normal.
+ * *Supercard Lite (slot-2):* It has been reported that only the
+ standard Supercard driver and the Moonshell version work with
+ ScummVM DS.
+ * *Datel Max Media Dock: * If you haven't already, upgrade your
+ firmware to the latest version. The firmware that came with my Max
+ Media Dock was unable to run ScummVM DS at all. Click here to
+ visit Datel's support page and download the latest firmware
+ <http://us.codejunkies.com/mpds/support.htm>
+ * *NinjaDS*: There are firmware upgrades for this device, but for
+ me, ScummVM DS ran straight out of the box. Visit this page
+ <http://www.ninjads.com/news.html> to download the latest firmware
+ if you want. If you have installed FlashMe on your DS, it will
+ make your DS crash on boot when the NinjaDS is inserted. You can
+ hold the 'select' button during boot to disable FlashMe, which
+ will allow the NinjaDS to work. Due to this, it is not recommended
+ to install FlashMe if you use a NinjaDS.
+ * *EZ-Flash*: This card reader uses .ds.gba files from the ScummVM
+ archive. Rename them to .nds before patching them with the DLDI
+ patcher.
+ * *R4DS*: If you upgrade the firmware for your R4DS to version 1.10
+ or later, the card will autmatically DLDI patch the game, meaning
+ you don't have to use dlditool to patch the .NDS file. This makes
+ things a lot easier!
+ * *M3DS Real*: This card autmatically DLDI patches the game, meaning
+ that you do not need to do this yourself.
+
+
+
+ Which games are compatible with ScummVM DS?
+ ------------------------------------------------------------------------
+
+I'm glad you asked. Here is a list of the compatible games in version
+0.12.0. Demo versions of the games listed should work too.
+
+Flight of the Amazon Queen, Beneath a Steel Sky, and Lure of the
+Temptress have generously been released as freeware by the original
+authors, Revolution Software <http://www.revolution.co.uk/>. This is a
+great thing and we should support Revolution for being so kind to us.
+You can download the game data from the official ScummVM download page
+<http://www.scummvm.org/downloads.php>.
+
+The other games on this list are commercial, and still under copyright,
+which means downloading them without paying for it is illegal. You can
+probably find a second-hand copy on eBay. Please don't email me to ask
+for a copy, as I am unable to send it to you.
+
+Game Build Notes
+
+Manic Mansion A
+
+Zak McKracken and the Alien Mindbenders A
+
+Indiana Jones and the Last Crusade A
+
+Loom A
+
+Passport to Adventure A
+
+The Secret of Monkey Island A
+
+Monkey Island 2: LeChuck's Revenge A
+
+Indiana Jones and the Fate of Atlantis A
+
+Day of the Tentacle A
+
+Sam & Max Hit the Road A Some slowdown in a few scenes
+ when MP3 audio is enabled
+
+Bear Stormin' (DOS) A
+
+Fatty Bear's Birthday Surprise (DOS) A
+
+Fatty Bear's Fun Pack (DOS) A
+
+Putt-Putt's Fun Pack (DOS) A
+
+Putt-Putt Goes to the Moon (DOS) A
+
+Putt-Putt Joins the Parade (DOS) A Can sometimes crash due to low memory
+
+Beneath a Steel Sky B
+
+Flight of the Amazon Queen B
+
+Simon the Sorcerer 1 C Zoomed view does not follow the
+ speaking character
+Simon the Sorcerer 2 C Zoomed view does not follow the
+ speaking character
+Elvira 1 C
+
+Elvira 2 C
+
+Waxworks (Amiga version) C
+
+Gobliiins D
+
+Gobliins 2 D
+
+Goblins 3 D
+
+Ween: The Prophecy D
+
+Bargon Attack D
+
+Lost in Time D
+
+Future Wars D
+
+All Sierra AGI games.
+For a complete list, see this page
+<http://wiki.scummvm.org/index.php/AGI> D
+
+Inherit the Earth E
+
+The Legend of Kyrandia F Zoomed view does not follow the
+ speaking character
+
+Lure of the Temptress G
+
+Nippon Safes G
+
+There is no support for Full Throttle, The Dig, or The Curse of Monkey
+Island because of memory issues. There simply is not enough RAM on the
+DS to run these games. Sorry. Also there is no support for Windows Humongous
+Entertainment games. The extra code required to make this work uses up
+too much RAM.
+
+
+ What to do when saving doesn't work or your card gets corrupted -
+ forcing SRAM Saves
+ ------------------------------------------------------------------------
+
+This method only works for cards which use the Game Boy Advance slot on the
+bottom of your DS.
+
+If ScummVM DS cannot save games to your SD card, or it causes corruption
+when it does, you can force it to use GBA SRAM to save the game. This
+uses your flash cart reader's GBA features to save the game to a .sav or
+.dat file (depending on the reader). Only slot-2 devices can use SRAM saves,
+and only ones with support for GBA games.
+
+If you want to use SRAM save, just create a text file called scummvm.ini
+(or scummvmb.ini, scummvmc.ini for builds B or C) in the root of your
+card which contains the following:
+
+[ds]
+forcesramsave=true
+
+When you boot your game, ScummVM DS will not save games to your SD card
+directly, instead it will save to GBA SRAM. On most cards, you need to
+transfer the data to your SD card by rebooting and using your card
+reader's boot-up menu. Using this method, around four saves can me made.
+
+One disadvantage of forcing SRAM saves is that your settings won't be
+saved. You can add games manually to the ini file so that you don't have
+to select them on each boot. Just add a section like the following on
+for each game on your card.
+
+[monkey2]
+description=Monkey Island 2: LeChuck's Revenge (English/DOS)
+path=mp:/MONKEY2
+
+
+ How to Use ScummVM
+ ------------------------------------------------------------------------
+
+Once you've booted up ScummVM, you'll see the start up screen.
+
+ 1. Tap the 'Add' button with the pen, then browse to the folder
+ containing your game data. Once you have clicked on your folder, you will
+ not see any files inside. This is normal, as the folder selector only shows
+ folders!
+
+ 2. Click the 'Choose' button.
+
+ 3. You will get some options for the game. You can usually just click 'Ok' to
+ this.
+
+ 4. Now click on the name of the game you want to play from the list and
+ click 'Start'. Your game will start!
+
+You can use the B button to skip cutscenes, and the select button to
+show an options menu which will let you tweak the DS contols, including
+switch between scaled and unscaled video modes. The text is clearer in
+the unscaled mode, but the whole game doesn't fit on the screen. To
+scroll around, hold either shoulder button and use the D-pad or drag the
+screen around with the stylus. Even in scaled mode, a small amount is
+missing from the top and bottom of the screen. You can scroll around to
+see those areas. The top screen shows a zoomed-in view. This scrolls
+around to focus on the character who's speaking, and also follows where
+the pen touches the screen. You can change the zoom level by holding one
+of the shoulder buttons and pressing B to zoom in and A to zoom out.
+
+Press the start button for the in-game menu where you can load or save
+your game (this works in Lucasarts games, other games vary). Saves will
+write directly to your flash card. You can choose the folder where they
+are stored using the GUI that appears when you boot up. If you're using
+a GBA Flash Cartridge, or an unsupported flash card adaptor, you will be
+using GBA SRAM to save your game. Four or five save game will fit in
+save RAM. If you save more games than will fit, a warning will appear on
+the top screen. When you turn your DS off, the new save will be lost,
+and only the first ones you saved will be present.
+
+Many of the games use both mouse buttons. Usually the right button often
+performs the default action on any object you click on. To simulate this
+with the DS pen, you can switch the input into one of three modes. Press
+left on the D-pad to enable the left mouse button. Press right on the
+D-pad to enable the right mouse button. Press up on the D-pad to enable
+hover mode. In this mode, you won't click on anything, just hover the
+mouse cursor over it. This lets you pick out active objects in the scene.
+
+An icon on the top screen will show you which mode you're in.
+
+In hover mode, there are some additional controls. While holding the pen
+on the screen, tapping D-pad left or D-pad right (or A/Y in left handed
+mode) will click the left or right mouse button.
+
+There is an alternative method of control which doesn't require you to
+change modes with the D-pad. Press 'Select' to bring up the DS options,
+and choose 'Tap for left click, double tap for right click'. In this
+mode, you can quickly tap the screen to left click the mouse, and tap twice
+to right click the mouse.
+
+
+Here is a complete list of controls in right-handed mode (the default
+setting):
+Key Usage
+Pad Left Left mouse button
+Pad Right Right mouse button
+Pad Up Hover mouse (no mouse button)
+Pad Down Skip dialogue line (for some Lucasarts games), Show inventory
+ (for Beneath a Steel Sky), Show active objects (for Simon the Sorceror)
+Start Pause/game menu (works in some games)
+Select DS Options
+B Skip cutscenes
+A Swap main screen and zoomed screen
+Y Show/Hide debug console
+X Show/Hide on-screen keyboard
+L + D-pad or L + Pen Scroll touch screen view
+L + B Zoom in
+L + A Zoom out
+
+
+
+And here's left-handed mode:
+Key Usage
+Y Left mouse button
+A Right mouse button
+X Hover mouse (no mouse button)
+B Skip dialogue line (for some Lucasarts games), Show inventory (for
+ Beneath a Steel Sky), Show active objects (for Simon the Sorceror)
+Start Pause/game menu (works in some games)
+Select DS Options
+D-pad down Skip cutscenes
+D-pad up Swap main screen and zoomed screen
+D-pad left Show/Hide debug console
+D-pad right Show/Hide on-screen keyboard
+R + D-pad or R + Pen Scroll touch screen view
+R + D-pad down Zoom in
+R + d-pad right Zoom out
+
+
+
+ Game-specific controls
+ ------------------------------------------------------------------------
+
+ * Sam and Max Hit the Road: The current cursor mode is displayed on
+ the top screen. Use d-pad right to switch mode.
+ * Indiana Jones games: If you get into a fight, press Select, and
+ check the box marked 'Use Indy Fighting Controls'.
+ Return to the game, then use the following controls to fight:
+
+ D-pad left: move left
+ D-pad right: move right
+ D-pad up: guard up
+ D-pad down: guard down
+ Y: guard middle
+ X: Punch high
+ A: Punch middle
+ B: Punch low
+ Left shoulder: Fight towards the left
+ Right shoulder: Fight towards the right
+
+ The icon on the top screen shows which way you're currently
+ facing. Remember to turn the option off when the fight ends, or
+ the normal controls won't work!
+ * Beneath a Steel Sky: Press D-pad down to show your inventory.
+ * Simon the Sorcerer 1/2: Press D-pad down to show active objects.
+ * AGI games: Press Start to show the menu bar.
+ * Bargon Attack: Press Start to hit F1 when you need to start the
+ game. Use the on-screen keyboard (hit X) to press other function keys.
+
+
+ DS Options Screen
+ ------------------------------------------------------------------------
+
+Pressing the 'select' button during any game to show the DS options
+screen. This screen shows options specific to the Nintendo DS version
+of ScummVM.
+
+Controls tab
+
+Indy Fight Controls - Enable fighting controls for the Indiana Jones
+games. See 'Game Specific Controls' for more information.
+
+Left handed Mode - Switch the controls on the D-pad with the controls
+on the A/B/X/Y buttons.
+
+Show mouse cursor - Shows the game's mouse cursor on the bottom screen.
+
+Snap to edges - makes it easier for the mouse controls to reach the edges
+of the screen. Useful for Beneath a Steel Sky and Goblins 3.
+
+Touch X offset - if your screen doesn't perform properly, this setting
+allows you to adjust when the cursor appears left or right relative to
+the screen's measured touch position.
+
+Touch Y offset - if your screen doesn't perform properly, this setting
+allows you to adjust when the cursor appears higher or lower relative to
+the screen's measured touch position.
+
+Use Laptop Trackpad-style cursor control - In this mode, use the lower
+screen to drag the cursor around, a bit like using a trackpad on a laptop.
+When this option is enabled, the following option is also enabled.
+
+Tap for left click, double tap for right click - In this mode, you can
+quickly tap on the screen to left click the mouse, or quickly
+double tap on the screen to right click the mouse. If you find clicking
+or double-clicking difficult, try and make a firmer touch on the screen,
+and keep the pen down for longer.
+
+Sensitivity - this bar adjusts the speed of cursor movement when laptop
+trackpad-style cursor control is enabled (see above).
+
+Graphics Tab
+
+Scaling options:
+
+Three scaling options are available for the main screen.
+
+Harware Scale - Scales using the DS hardware scaler using a flicker method.
+Produces lower quality graphics but doesn't slow the game down.
+
+Software Scale - Scales using the CPU. A much higher quality image is
+produced, but at the expense of speed in some games.
+
+Unscaled - Allows you to see the graphics as originaly displayed. This
+doesn't fit on the DS screen, but you can scroll the screen around by holding
+the left shoulder button and using the D-pad or touch screen.
+
+Top screen zoom - These three options control the zoom level of the top
+screen when ScummVM is started up. Changing this option will set the zoom
+to the specified level immediately.
+
+Initial top screen scale:
+
+This option controls the scaling level of the zoomed screen. In ScummVM
+DS, one screen shows a zoomed-in view of the action, and this option controls
+how zoomed in it is. You can also adjust this in the game by holding L and
+pressing A/B.
+
+General Tab
+
+High Quality Audio - Enhance the sound quality, at the expense of some
+slowdown during some games.
+
+Disable power off - ScummVM DS turns the power off when the game quits.
+This option disables that feature.
+
+
+
+
+
+
+ Auto completion dictionary for Sierra AGI games
+ ------------------------------------------------------------------------
+
+If you are playing a Sierra AGI game, you will be using the on-screen
+keyboard quite a lot (press X to show it). To reduce the amount you have
+to type, the game can automatically complete long words for you. To use
+this feature, simply copy the PRED.DIC file from the ScummVM DS archive
+into your game folder on your card. Now, when you use the keyboard,
+possible words will be shown underneith it. To type one of those words,
+simply double click on it with your stylus.
+
+
+ Converting your CD audio
+ ------------------------------------------------------------------------
+
+ScummVM supports playing CD audio for specific games which came with
+music stored as standard music CD tracks. To use this music in ScummVM
+DS, they need to be ripped from the CD and stored in a specific format.
+This can only be done for the CD versions of certain games, such as
+Monkey Island 1, Loom, and Gobliiins. All the floppy games and CD games
+that didn't have CD audio tracks for music don't require any conversion,
+and will work unmodified on ScummVM DS. MP3 audio files for CD music are
+not supported.
+
+Cdex can do the conversion very well and I recommend using it to convert
+your audio files, although any CD ripping software can be used, so feel
+free to use your favourite program. The format you need to use is
+IMA-ADPCM 4-bit Mono. You may use any sample rate. All other formats
+will be rejected, including uncompressed WAV files.
+
+Now I will to describe how to rip your CD tracks with Cdex, which can be
+found here: Cdex Homepage <http://sourceforge.net/projects/cdexos/>.
+Other software can be used to create IMA ADPCM files under Linux or
+MacOS.
+
+To set this up in Cdex, select Settings from the Options menu. On the
+Encoder tab, select 'WAV Output Encoder'. Under 'Encoder Options',
+choose the following:
+
+ Format: WAV
+ Compression: IMA ADPCM
+ Samplerate: 22050 Hz
+ Channels: Mono
+ On the fly encoding: On
+
+Next, go to the 'Filenames' tab and select the folder you want to save
+your Wav files to. Under 'Filename format', enter 'track%3'. This should
+name your WAV files in the correct way. Click OK.
+
+Now select all the tracks on your CD, and click 'Extract CD tracks to a
+compressed audio file'. Cdex should rip all the audio off your CD.
+
+Now all you have to do is copy the newly created WAV files into the same
+directory that your other game data is stored on your CompactFlash card.
+Next time your run ScummVM DS, it should play with music!
+
+*Important Note:* Do not select 'Extract CD tracks to a WAV file'. This
+creates uncompressed WAVs only. You want 'Extract CD tracks to a
+compressed audio file'.
+
+
+ Converting Speech files to MP3 format
+ ------------------------------------------------------------------------
+
+ScummVM supports playing back speech for talkie games in MP3 format.
+Unfortunately, the DS CPU is not quite up to the task, and MP3 audio
+will sometimes cause slowdown in your game. However, if your flash card
+isn't big enough to fit the audio files on, you will have no choice!
+
+To convert your audio you will need a copy of the ScummVM Tools package
+<http://sourceforge.net/project/showfiles.php?group_id=37116&package_id=67433>.
+You will also need a copy of the LAME MP3 encoder
+<http://www.free-codecs.com/Lame_Encoder_download.htm>.
+
+Once this is all installed and set up, the process to encode your audio
+varies from game to game, but the Lucasarts games can all be compressed
+using the following command line:
+
+compress_scumm_sou --mp3 monster.sou
+
+This produces a monster.so3 file which you can copy to your flash card
+and replaces the original monster.sou. Ogg format (monster.sog) and flac
+format files are not currently supported by ScummVM DS, and it is
+unlikely they will ever be supported. There is no way to convert .sog or
+.so3 files back to .sou files. Just dig out your original CD and copy
+the file from that.
+
+
+ Frequently Asked Questions
+ ------------------------------------------------------------------------
+
+I get a lot of email about ScummVM DS. Nearly all of them are exactly
+the same. Here I'm going to try and answer the questions that everybody
+asks me in the hope that I will spend less time answering questions that
+are clearly in the documentation and more time helping people who have a
+real problem or have discovered a real bug.
+
+*Q:* I can't see the bottom line of inventory items in Day of the
+Tentacle, Monkey Island 2, or a few other games! What do I do?
+*A:* Hold down the left shoulder button and use D-pad (or the touch
+screen) to scroll the screen around.
+
+*Q:* I dont see a menu when I press Start in Flight of the Amazon Queen
+or Simon the Sorcerer. Is ScummVM broken?
+*A:* No. To save in Simon the Sorcerer, click 'use', then click on the
+postcard in your inventory. In Flight of the Amazon Queen, click 'use',
+then click on the journal in your inventory.
+
+*Q:* Why does ScummVM crash when I play Monkey Island 1?
+*A:* This happens when MP3 audio tracks are present from the PC version
+of ScummVM. Delete the MP3 tracks and reencode them to ADPCM WAV files
+as described in the CD audio section.
+
+*Q:* When will you support my Mini/Micro SD card reader? I want it!
+Pretty please?
+*A:* ScummVM uses DLDI drivers. If your card reader manufacturer doesn't
+provide a driver, there is nothing I can do about it. The people to ask
+are the card reader manufacturers themselves.
+
+*Q:* Can't you use the extra RAM in the M3/Supercard or the official
+Opera Expansion Pack to support more games like The Dig and Full
+Throttle? DS Linux has done it, so why can't you?
+*A:* Not at the moment. The extra RAM has certain differences to the
+build in RAM which makes it difficult to use for general programs. As
+ScummVM DS is an official port, the changes to the ScummVM code base
+must be minimal to avoid making the code difficult to read for other
+users. I do have plans to work on this some time in the future, but
+don't nag me about when it'll be done. If and when there's progress with
+this, I will post on the ScummVM forums about it.
+
+
+*Q:* ScummVM DS turns off my DS when I hit 'Quit' in the game or quit
+from the frontend. Why doesn't it return to the menu?
+*A:* Due to bugs in the ScummVM codebase, many of the ScummVM games
+cannot quit cleanly leaving the machine in the same state as when it
+started. You will notice that no other versions of ScummVM can quit back
+to the menu either. This will be fixed at some time in the future.
+
+
+
+
+ Contributors
+ ------------------------------------------------------------------------
+
+ScummVM DS uses chishm's GBA Movie Player FAT driver.
+The CPU scaler is by Tramboi and Robin Watts
+The ARM code was optimised by Robin Watts
+Thanks to highpass for the ScummVM DS icons.
+Thanks to zhevon for the Sam & Max cursor code.
+Thanks to theNinjaBunny for the M3 Adaptor guide on this site.
+Thanks also to everyone on the GBADev Forums.
+
+This program was brought to you by caffiene, sugar, and late nights.
+
+
+ Donations and Getting Help
+ ------------------------------------------------------------------------
+
+If you have problems getting ScummVM to work on your hardware, please
+read the FAQ first. /Please/ don't ask me questions which are
+answered in the FAQ, I get many emails about this program each day, and
+I can't help the people who really need help if I'm answering the same
+question all the time which is already answered on this page. Other than
+that, feel free to post on the ScummVM DS forum <http://forums.scummvm.org>
+for help. Please do your research first though. There is no way of
+running this on an out-of-the box DS without extra hardware. Most of
+these things are fairly inexpensive though.
+
+If you want to contact me, please email me on scummvm at millstone dot
+demon dot co dot uk.
+
+If you want to help with the development of ScummVM DS, great! Download
+the source code and get building. There are plenty of things left to do.
+
+You can also help by making a donation if you've particularly enjoyed
+ScummVM DS. This uses Paypal, and is completely secure. There's no
+pressure though, ScummVM DS is completely free. This is just for those
+who would like to make a contribution to further development.
+
+
+
+ Building from Sources
+ ------------------------------------------------------------------------
+
+ScummVM is an open source project. This means that anyone is free to
+take the source code to the project and make their own additions and fixes,
+contributing them back to the authors for consideration for the next version.
+
+To build ScummVM DS from source, it's probably better to checkout the
+latest version of the code from the ScummVM SVN repository. The ScummVM
+Sourceforge.net homepage <http://sourceforge.net/projects/scummvm> has
+all the information about how to do this.
+
+By default, ScummVM DS expects to find libmad, an MP3 compressor library
+targeted for the ARM platform. If you don't have this, you must disable
+libmad support by opening 'backends/platform/ds/arm9/makefile' and
+commenting out the line which says USE_MAD = 1.
+
+Then, enter the 'backends/platform/ds' folder and type:
+make SCUMM_BUILD=a
+
+The executable nds file will build inside 'backends/platform/ds/arm9/SCUMMVM-A'.
+
+For other builds, substitute the letters b - g in the above line.
+
+
+
diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile
index 7472a32218..e74bcf28da 100644
--- a/backends/platform/ds/arm9/makefile
+++ b/backends/platform/ds/arm9/makefile
@@ -8,25 +8,29 @@ libndsdir = $(DEVKITPRO)/libnds
# Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g.
# Anything else gets build a.
-ifeq ($(SCUMM_BUILD),g)
+ifeq ($(SCUMM_BUILD),h)
+ DS_BUILD_H = 1
+ else
+ ifeq ($(SCUMM_BUILD),g)
DS_BUILD_G = 1
-else
- ifeq ($(SCUMM_BUILD),f)
+ else
+ ifeq ($(SCUMM_BUILD),f)
DS_BUILD_F = 1
- else
- ifeq ($(SCUMM_BUILD),e)
- DS_BUILD_E = 1
else
- ifeq ($(SCUMM_BUILD),d)
- DS_BUILD_D = 1
+ ifeq ($(SCUMM_BUILD),e)
+ DS_BUILD_E = 1
else
- ifeq ($(SCUMM_BUILD),c)
- DS_BUILD_C = 1
+ ifeq ($(SCUMM_BUILD),d)
+ DS_BUILD_D = 1
else
- ifeq ($(SCUMM_BUILD),b)
- DS_BUILD_B = 1
+ ifeq ($(SCUMM_BUILD),c)
+ DS_BUILD_C = 1
else
+ ifeq ($(SCUMM_BUILD),b)
+ DS_BUILD_B = 1
+ else
DS_BUILD_A = 1
+ endif
endif
endif
endif
@@ -67,7 +71,12 @@ endif
# NOTE: The header and libs for the debugger is assumed to be in the libnds
# folder.
-VPATH = $(srcdir)
+vpath %.h $(srcdir)
+vpath %.cpp $(srcdir)
+vpath %.c $(srcdir)
+vpath %.m $(srcdir)
+vpath %.asm $(srcdir)
+vpath %.s $(srcdir)
# Command to build libmad is:
# ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork'
@@ -75,8 +84,8 @@ VPATH = $(srcdir)
# I actually had to use
# ./configure --host=arm-elf --enable-speed --enable-sso -enable-fpm=arm CFLAGS='-specs=ds_arm9.specs -mthumb-interwork' LDFLAGS='C:/Progra~1/devkitpro/libnds/lib/libnds9.a' --disable-shared --disable-debugging
-USE_ARM_SOUND_ASM = 1
ARM = 1
+USE_ARM_SOUND_ASM = 1
USE_ARM_COSTUME_ASM = 1
ifdef DS_BUILD_A
@@ -135,6 +144,13 @@ ifdef DS_BUILD_G
BUILD=scummvm-G
endif
+ifdef DS_BUILD_H
+ DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_H
+ LOGO = logog.bmp
+ ENABLE_PARALLACTION = STATIC_PLUGIN
+ BUILD=scummvm-H
+endif
+
ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin
ICON := -b ../../../logo.bmp "ScummVM;By Neil Millstone;"
@@ -147,6 +163,7 @@ CFLAGS = -Wno-multichar -Wall\
-mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
-mthumb-interwork -DUSE_ARM_COSTUME_ASM=1
+
# -ffast-math
ifdef USE_DEBUGGER
@@ -160,7 +177,7 @@ ifdef USE_PROFILER
endif
CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \
- -fno-exceptions -fno-rtti -mthumb-interwork
+ -fno-exceptions -fno-rtti -mthumb-interwork -ffunction-sections -fdata-sections
# -mthumb
@@ -180,12 +197,12 @@ ifdef USE_MAD
endif
-LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt
+LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -Wl,--wrap,time -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections
-INCLUDES= -I./ -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/common -I$(portdir)/source \
- -I$(portdir)/data -I$(libndsdir)/include -I$(portdir)/../commoninclude\
- -I$(libndsdir)/include -I$(libndsdir)/include/nds -I$(srcdir)/engines -I$(portdir)/source/mad\
- -I$(portdir)/source/libcartreset -include $(srcdir)/common/scummsys.h
+INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \
+ -I$(portdir)/data -I$(portdir)/../commoninclude \
+ -I$(portdir)/source -I$(portdir)/source/mad -I$(portdir)/source/libcartreset \
+ -I$(libndsdir)/include -include $(srcdir)/common/scummsys.h
LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9
@@ -232,7 +249,8 @@ endif
DATA_OBJS := $(portdir)/data/icons.o $(portdir)/data/keyboard.o $(portdir)/data/keyboard_pal.o $(portdir)/data/default_font.o $(portdir)/data/8x8font_tga.o
-COMPRESSOR_OBJS := $(portdir)/source/compressor/lz.o
+COMPRESSOR_OBJS :=
+#$(portdir)/source/compressor/lz.o
FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o\
$(portdir)/source/fat/io_fcsr.o $(portdir)/source/fat/io_m3cf.o\
@@ -252,14 +270,15 @@ FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o
# $(portdir)/source/fat/io_sd_common.o $(portdir)/source/fat/io_scsd_s.o \
# $(portdir)/source/fat/io_sc_common.o $(portdir)/source/fat/io_sd_common.o
-LIBCARTRESET_OBJS := $(portdir)/source/libcartreset/cartreset.o
+LIBCARTRESET_OBJS :=
+#$(portdir)/source/libcartreset/cartreset.o
# Files in this list will be optimisied for speed, otherwise they will be optimised for space
OPTLIST := actor.cpp ds_main.cpp osystem_ds.cpp blitters.cpp fmopl.cpp rate.cpp mixer.cpp isomap.cpp image.cpp gfx.cpp sprite.cpp actor_path.cpp actor_walk.cpp
#OPTLIST :=
# Compiler options for files which should be optimised for speed
-OPT_SPEED := -O2
+OPT_SPEED := -O3
# Compiler options for files which should be optimised for space
OPT_SIZE := -Os
@@ -281,7 +300,7 @@ ndsall:
include $(srcdir)/Makefile.common
semiclean:
- $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o
+ $(RM) $(portdir)/source/dsoptions.o $(portdir)/source/dsmain.o $(FAT_OBJS) $(DATA_OBJS) $(portdir)/source/wordcompletion.o $(portdir)/source/dsoptions.o
clean:
$(RM) $(OBJS) $(EXECUTABLE)
@@ -333,36 +352,17 @@ endef
##############
# Replacement rule for the one in makefile.common
##############
-ifndef HAVE_GCC3
-# If you use GCC, disable the above and enable this for intelligent
-# dependency tracking.
-#.cpp.o:
-%.o:%.cpp
- $(MKDIR) $(*D)/$(DEPDIR)
- $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
-# $(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d
- $(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d"
- $(RM) "$(*D)/$(DEPDIR)/$(*F).d2"
-else
-# If you even have GCC 3.x, you can use this build rule, which is safer; the above
-# rule can get you into a bad state if you Ctrl-C at the wrong moment.
-# Also, with this GCC inserts additional dummy rules for the involved headers,
-# which ensures a smooth compilation even if said headers become obsolete.
-#.cpp.o:
-%.o:%.cpp
+%.o: %.cpp
# echo !!!!!!!!!!!! $(notdir $<)
# ifeq ( $(notdir $<), $(findstring $(notdir $<), $(OPTLIST)) )
# OPTFLAG=-O3
# else
# OPTFLAG=-Os
# endif
-
# export OPTFLAG = ;
# echo !!!!!!!! $(OPTFLAG)
-
$(MKDIR) $(*D)/$(DEPDIR)
$(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(if $(findstring $(notdir $<), $(OPTLIST)), $(OPT_SPEED), $(OPT_SIZE)) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
-endif
#---------------------------------------------------------------------------------
@@ -412,6 +412,7 @@ endif
padbin 16 $(basename $@).ds.gba
#---------------------------------------------------------------------------------
+# FIXME: The following rule hardcodes the input & output filename -- shouldn't it use $< and $@ instead?
%.bin: %.elf
$(OBJCOPY) -S scummvm.elf scummvm-stripped.elf
$(OBJCOPY) -O binary scummvm-stripped.elf scummvm.bin
@@ -419,4 +420,3 @@ endif
#%.o: %.s
# $(MKDIR) $(*D)/$(DEPDIR)
# $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
-
diff --git a/backends/platform/ds/arm9/source/blitters_arm.s b/backends/platform/ds/arm9/source/blitters_arm.s
index 5f7df298b4..48ec316675 100644
--- a/backends/platform/ds/arm9/source/blitters_arm.s
+++ b/backends/platform/ds/arm9/source/blitters_arm.s
@@ -20,149 +20,12 @@
@
@ @author Robin Watts (robin@wss.co.uk)
- .global asmDrawStripToScreen
- .global asmCopy8Col
.global Rescale_320x256xPAL8_To_256x256x1555
.global Rescale_320x256x1555_To_256x256x1555
.section .itcm,"ax", %progbits
.align 2
.code 32
- @ ARM implementation of asmDrawStripToScreen.
- @
- @ C prototype would be:
- @
- @ extern "C" void asmDrawStripToScreen(int height,
- @ int width,
- @ byte const *text,
- @ byte const *src,
- @ byte *dst,
- @ int vsPitch,
- @ int vsScreenWidth,
- @ int textSurfacePitch);
- @
- @ In addition, we assume that text, src and dst are all word (4 byte)
- @ aligned. This is the same assumption that the old 'inline' version
- @ made.
-asmDrawStripToScreen:
- @ r0 = height
- @ r1 = width
- @ r2 = text
- @ r3 = src
- MOV r12,r13
- STMFD r13!,{r4-r7,r9-r11,R14}
- LDMIA r12,{r4,r5,r6,r7}
- @ r4 = dst
- @ r5 = vsPitch
- @ r6 = vmScreenWidth
- @ r7 = textSurfacePitch
-
- CMP r0,#0 @ If height<=0
- MOVLE r0,#1 @ height=1
- CMP r1,#4 @ If width<4
- BLT end @ return
-
- @ Width &= ~4 ? What's that about then? Width &= ~3 I could have
- @ understood...
- BIC r1,r1,#4
-
- SUB r5,r5,r1 @ vsPitch -= width
- SUB r6,r6,r1 @ vmScreenWidth -= width
- SUB r7,r7,r1 @ textSurfacePitch -= width
- MOV r10,#253
- ORR r10,r10,r10,LSL #8
- ORR r10,r10,r10,LSL #16 @ r10 = mask
-yLoop:
- MOV r14,r1 @ r14 = width
-xLoop:
- LDR r12,[r2],#4 @ r12 = [text]
- LDR r11,[r3],#4 @ r11 = [src]
- CMP r12,r10
- BNE singleByteCompare
- SUBS r14,r14,#4
- STR r11,[r4], #4 @ r4 = [dst]
- BGT xLoop
-
- ADD r2,r2,r7 @ text += textSurfacePitch
- ADD r3,r3,r5 @ src += vsPitch
- ADD r4,r4,r6 @ dst += vmScreenWidth
- SUBS r0,r0,#1
- BGT yLoop
- LDMFD r13!,{r4-r7,r9-r11,PC}
-
-singleByteCompare:
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- STR r12,[r4],#4
- SUBS r14,r14,#4
- BGT xLoop
-
- ADD r2,r2,r7 @ text += textSurfacePitch
- ADD r3,r3,r5 @ src += vsPitch
- ADD r4,r4,r6 @ dst += vmScreenWidth
- SUBS r0,r0,#1
- BGT yLoop
-end:
- LDMFD r13!,{r4-r7,r9-r11,PC}
-
-
- @ ARM implementation of asmCopy8Col
- @
- @ C prototype would be:
- @
- @ extern "C" void asmCopy8Col(byte *dst,
- @ int dstPitch,
- @ const byte *src,
- @ int height);
- @
- @ In addition, we assume that src and dst are both word (4 byte)
- @ aligned. This is the same assumption that the old 'inline' version
- @ made.
-asmCopy8Col:
- @ r0 = dst
- @ r1 = dstPitch
- @ r2 = src
- @ r3 = height
- STMFD r13!,{r14}
- SUB r1,r1,#4
-
- TST r3,#1
- ADDNE r3,r3,#1
- BNE roll2
-yLoop2:
- LDR r12,[r2],#4
- LDR r14,[r2],r1
- STR r12,[r0],#4
- STR r14,[r0],r1
-roll2:
- LDR r12,[r2],#4
- LDR r14,[r2],r1
- SUBS r3,r3,#2
- STR r12,[r0],#4
- STR r14,[r0],r1
- BNE yLoop2
-
- LDMFD r13!,{PC}
-
-
@ ARM implementation of Rescale_320x256x1555_To_256x256x1555
@
@ C prototype would be:
diff --git a/backends/platform/ds/arm9/source/cdaudio.h b/backends/platform/ds/arm9/source/cdaudio.h
index d237569bb7..d1897d3e5d 100644
--- a/backends/platform/ds/arm9/source/cdaudio.h
+++ b/backends/platform/ds/arm9/source/cdaudio.h
@@ -20,7 +20,7 @@
*
*/
- #ifndef _CDAUDIO_H_
+#ifndef _CDAUDIO_H_
#define _CDAUDIO_H_
namespace DS {
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index f4706807f7..872a196e9b 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -65,6 +65,8 @@
//#define USE_LIBCARTRESET
#include <nds.h>
+#include <nds/registers_alt.h>
+#include <nds/arm9/exceptions.h>
//#include <ARM9/console.h> //basic print funcionality
@@ -75,13 +77,10 @@
#include "icons_raw.h"
#include "fat/gba_nds_fat.h"
#include "fat/disc_io.h"
-#include "common/config-manager.h"
-#include "engines/scumm/scumm.h"
#include "keyboard_raw.h"
#include "keyboard_pal_raw.h"
#define V16(a, b) ((a << 12) | b)
#include "touchkeyboard.h"
-#include "registers_alt.h"
//#include "compact_flash.h"
#include "dsoptions.h"
#ifdef USE_DEBUGGER
@@ -96,6 +95,26 @@
#endif
#include "backends/fs/ds/ds-fs.h"
+extern "C" u32 getExceptionAddress( u32 opcodeAddress, u32 thumbState);
+extern const char __itcm_start[];
+static const char *registerNames[] =
+ { "r0","r1","r2","r3","r4","r5","r6","r7",
+ "r8 ","r9 ","r10","r11","r12","sp ","lr ","pc " };
+
+/*
+extern "C" void* __real_malloc(size_t size);
+
+extern "C" void* __wrap_malloc(size_t size) {
+ void* res = __real_malloc(size);
+ if (res) {
+ return res;
+ } else {
+ consolePrintf("Failed alloc %d\n", size);
+ return NULL;
+ }
+}
+*/
+
namespace DS {
// From console.c in NDSLib
@@ -168,7 +187,7 @@ bool displayModeIs8Bit = false;
u8 gameID;
bool snapToBorder = false;
-bool consoleEnable = true;
+bool consoleEnable = false;
bool gameScreenSwap = false;
bool isCpuScalerEnabled();
//#define HEAVY_LOGGING
@@ -197,6 +216,13 @@ int mouseHotspotX, mouseHotspotY;
bool cursorEnable = false;
bool mouseCursorVisible = true;
bool rightButtonDown = false;
+bool touchPadStyle = false;
+int touchPadSensitivity = 8;
+bool tapScreenClicks = true;
+
+int tapCount = 0;
+int tapTimeout = 0;
+int tapComplete = 0;
// Dragging
int dragStartX, dragStartY;
@@ -213,7 +239,14 @@ int gameHeight = 200;
// Scale
bool twoHundredPercentFixedScale = false;
bool cpuScalerEnable = false;
-#define NUM_SUPPORTED_GAMES 20
+
+ // 100 256
+ // 150 192
+ // 200 128
+
+ // (256 << 8) / scale
+
+
#ifdef USE_PROFILER
int hBlankCount = 0;
@@ -221,6 +254,7 @@ int hBlankCount = 0;
u8* scalerBackBuffer = NULL;
+#define NUM_SUPPORTED_GAMES 21
gameListType gameList[NUM_SUPPORTED_GAMES] = {
// Unknown game - use normal SCUMM controls
@@ -248,6 +282,7 @@ gameListType gameList[NUM_SUPPORTED_GAMES] = {
{"elvira2", CONT_SIMON},
{"elvira1", CONT_SIMON},
{"waxworks", CONT_SIMON},
+ {"parallaction", CONT_NIPPON},
};
gameListType* currentGame = NULL;
@@ -260,6 +295,7 @@ bool penHeld;
bool penReleased;
bool penDownLastFrame;
s32 penX, penY;
+s32 penDownX, penDownY;
int keysDownSaved;
int keysReleasedSaved;
int keysChangedSaved;
@@ -299,9 +335,41 @@ void setCpuScalerEnable(bool enable) {
cpuScalerEnable = enable;
}
+void setTrackPadStyleEnable(bool enable) {
+ touchPadStyle = enable;
+}
+
+void setTapScreenClicksEnable(bool enable) {
+ tapScreenClicks = enable;
+}
+
+void setGameScreenSwap(bool enable) {
+ gameScreenSwap = enable;
+}
+
+void setSensitivity(int sensitivity) {
+ touchPadSensitivity = sensitivity;
+}
+
+void setTopScreenZoom(int percentage) {
+ // 100 256
+ // 150 192
+ // 200 128
+
+ // (256 << 8) / scale
+
+ s32 scale = (percentage << 8) / 100;
+ subScreenScale = (256 * 256) / scale;
+
+// consolePrintf("Scale is %d %%\n", percentage);
+}
// return (ConfMan.hasKey("cpu_scaler", "ds") && ConfMan.getBool("cpu_scaler", "ds"));
+controlType getControlType() {
+ return currentGame->control;
+}
+
//plays an 8 bit mono sample at 11025Hz
void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate)
@@ -429,14 +497,14 @@ void initGame() {
consolePrintf("initing game...");
#endif
- static bool firstTime = true;
+// static bool firstTime = true;
setOptions();
//strcpy(gameName, ConfMan.getActiveDomain().c_str());
strcpy(gameName, ConfMan.get("gameid").c_str());
- consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
+// consolePrintf("\n\n\n\nCurrent game: '%s' %d\n", gameName, gameName[0]);
currentGame = &gameList[0]; // Default game
@@ -447,16 +515,12 @@ void initGame() {
}
}
- if (firstTime) {
+/* if (firstTime) {
firstTime = false;
- if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) {
- startSound(22050, 8192);
- } else {
- startSound(11025, 4096);
- }
}
+*/
#ifdef HEAVY_LOGGING
consolePrintf("done\n");
#endif
@@ -631,7 +695,7 @@ void checkSleepMode() {
void setShowCursor(bool enable)
{
- if (currentGame->control == CONT_SCUMM_SAMNMAX)
+ if ((currentGame) && (currentGame->control == CONT_SCUMM_SAMNMAX))
{
if (cursorEnable) {
sprites[1].attribute[0] = ATTR0_BMP | 150;
@@ -654,23 +718,28 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX,
mouseHotspotX = hotspotX;
mouseHotspotY = hotspotY;
+ //consolePrintf("Set cursor icon %d, %d\n", w, h);
+
{
int off = 128*64;
memset(SPRITE_GFX + off, 0, 32 * 32 * 2);
memset(SPRITE_GFX_SUB + off, 0, 32 * 32 * 2);
+
for (uint y=0; y<h; y++) {
for (uint x=0; x<w; x++) {
int color = icon[y*w+x];
+
+ //consolePrintf("%d:%d ", color, OSystem_DS::instance()->getDSPaletteEntry(color));
if (color == keycolor) {
SPRITE_GFX[off+(y)*32+x] = 0x0000; // black background
SPRITE_GFX_SUB[off+(y)*32+x] = 0x0000; // black background
} else {
- SPRITE_GFX[off+(y)*32+x] = BG_PALETTE[color] | 0x8000;
- SPRITE_GFX_SUB[off+(y)*32+x] = BG_PALETTE[color] | 0x8000;
+ SPRITE_GFX[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000;
+ SPRITE_GFX_SUB[off+(y)*32+x] = OSystem_DS::instance()->getDSCursorPaletteEntry(color) | 0x8000;
}
}
}
@@ -733,6 +802,7 @@ void setCursorIcon(const u8* icon, uint w, uint h, byte keycolor, int hotspotX,
sprites[1].attribute[1] = ATTR1_SIZE_64 | pos;
sprites[1].attribute[2] = ATTR2_ALPHA(1) | 176;
}
+
}
@@ -745,6 +815,7 @@ void displayMode16Bit() {
u16 buffer[32 * 32 * 2];
+ releaseAllKeys();
if (displayModeIs8Bit) {
// static int test = 0;
@@ -1109,7 +1180,7 @@ void setKeyboardEnable(bool en) {
} else {
-
+ DS::releaseAllKeys();
// Restore the palette that the keyboard has used
for (int r = 0; r < 256; r++) {
BG_PALETTE_SUB[r] = BG_PALETTE[r];
@@ -1157,6 +1228,194 @@ bool getIsDisplayMode8Bit() {
return displayModeIs8Bit;
}
+void doScreenTapMode(OSystem_DS* system)
+{
+ Common::Event event;
+ static bool left = false, right = false;
+
+ if (left) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ left = false;
+ }
+
+ if (right) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ right = false;
+ }
+
+
+ if (tapComplete == 1) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ tapComplete = 0;
+ left = true;
+ } else if (tapComplete == 2) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ tapComplete = 0;
+ right = true;
+ }
+
+
+ if (getKeysDown() & KEY_LEFT) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+ if (getKeysReleased() & KEY_LEFT) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+
+ if (getKeysDown() & KEY_RIGHT) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+ if (getKeysReleased() & KEY_RIGHT) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+}
+
+void doButtonSelectMode(OSystem_DS* system)
+{
+ Common::Event event;
+
+
+ if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ //consolePrintf("x=%d y=%d \n", getPenX(), getPenY());
+ }
+
+ static bool leftButtonDown = false;
+ static bool rightButtonDown = false;
+
+ if (getPenReleased() && (leftButtonDown || rightButtonDown)) {
+ if (leftButtonDown) {
+ event.type = Common::EVENT_LBUTTONUP;
+ } else {
+ event.type = Common::EVENT_RBUTTONUP;
+ }
+
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+
+ if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
+ if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
+ if ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit)) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ leftButtonDown = true;
+ } else {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ rightButtonDown = true;
+ }
+
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+ } else {
+ // In hover mode, D-pad left and right click the mouse when the pen is on the screen
+
+ if (getPenHeld()) {
+ if (getKeysDown() & KEY_LEFT) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+ if (getKeysReleased() & KEY_LEFT) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+
+
+ if (getKeysDown() & KEY_RIGHT) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+ if (getKeysReleased() & KEY_RIGHT) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ system->addEvent(event);
+ }
+ }
+ }
+
+ if (!((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) && (!getIndyFightState()) && (!getKeyboardEnable())) {
+
+ if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) {
+ if (getKeysDown() & KEY_LEFT) {
+ mouseMode = MOUSE_LEFT;
+ }
+
+ if (rightButtonDown)
+ {
+ Common::Event event;
+ event.mouse = Common::Point(getPenX(), getPenY());
+ event.type = Common::EVENT_RBUTTONUP;
+ system->addEvent(event);
+ rightButtonDown = false;
+ }
+
+
+ if (getKeysDown() & KEY_RIGHT) {
+ if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) {
+ mouseMode = MOUSE_RIGHT;
+ } else {
+ // If we're playing sam and max, click and release the right mouse
+ // button to change verb
+ Common::Event event;
+
+ if (currentGame->control == CONT_FUTURE_WARS) {
+ event.mouse = Common::Point(320 - 128, 200 - 128);
+ event.type = Common::EVENT_MOUSEMOVE;
+ system->addEvent(event);
+ } else {
+ event.mouse = Common::Point(getPenX(), getPenY());
+ }
+
+ rightButtonDown = true;
+
+
+ event.type = Common::EVENT_RBUTTONDOWN;
+ system->addEvent(event);
+
+ //event.type = Common::EVENT_RBUTTONUP;
+ //system->addEvent(event);
+ }
+ }
+
+
+
+ if (getKeysDown() & KEY_UP) {
+ mouseMode = MOUSE_HOVER;
+ }
+ }
+ }
+}
+
void addEventsToQueue() {
#ifdef HEAVY_LOGGING
consolePrintf("addEventsToQueue\n");
@@ -1286,54 +1545,6 @@ void addEventsToQueue() {
}
- if (!getPenHeld() || (mouseMode != MOUSE_HOVER)) {
- if (getKeysDown() & KEY_LEFT) {
- mouseMode = MOUSE_LEFT;
- }
-
- if (rightButtonDown)
- {
- Common::Event event;
- event.mouse = Common::Point(getPenX(), getPenY());
- event.type = Common::EVENT_RBUTTONUP;
- system->addEvent(event);
- rightButtonDown = false;
- }
-
-
- if (getKeysDown() & KEY_RIGHT) {
- if ((currentGame->control != CONT_SCUMM_SAMNMAX) && (currentGame->control != CONT_FUTURE_WARS) && (currentGame->control != CONT_GOBLINS)) {
- mouseMode = MOUSE_RIGHT;
- } else {
- // If we're playing sam and max, click and release the right mouse
- // button to change verb
- Common::Event event;
-
- if (currentGame->control == CONT_FUTURE_WARS) {
- event.mouse = Common::Point(320 - 128, 200 - 128);
- event.type = Common::EVENT_MOUSEMOVE;
- system->addEvent(event);
- } else {
- event.mouse = Common::Point(getPenX(), getPenY());
- }
-
- rightButtonDown = true;
-
-
- event.type = Common::EVENT_RBUTTONDOWN;
- system->addEvent(event);
-
- //event.type = Common::EVENT_RBUTTONUP;
- //system->addEvent(event);
- }
- }
-
-
-
- if (getKeysDown() & KEY_UP) {
- mouseMode = MOUSE_HOVER;
- }
- }
@@ -1359,52 +1570,13 @@ void addEventsToQueue() {
if (!keyboardEnable) {
- if ((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
- event.type = Common::EVENT_MOUSEMOVE;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- //consolePrintf("x=%d y=%d \n", getPenX(), getPenY());
+ if ((tapScreenClicks) && (getIsDisplayMode8Bit()))
+ {
+ doScreenTapMode(system);
}
-
- if ((mouseMode != MOUSE_HOVER) || (!displayModeIs8Bit)) {
- if (getPenDown() && (!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R))) {
- event.type = ((mouseMode == MOUSE_LEFT) || (!displayModeIs8Bit))? Common::EVENT_LBUTTONDOWN: Common::EVENT_RBUTTONDOWN;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
-
- if (getPenReleased()) {
- event.type = mouseMode == MOUSE_LEFT? Common::EVENT_LBUTTONUP: Common::EVENT_RBUTTONUP;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
- } else {
- // In hover mode, D-pad left and right click the mouse when the pen is on the screen
-
- if (getPenHeld()) {
- if (getKeysDown() & KEY_LEFT) {
- event.type = Common::EVENT_LBUTTONDOWN;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
- if (getKeysReleased() & KEY_LEFT) {
- event.type = Common::EVENT_LBUTTONUP;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
-
-
- if (getKeysDown() & KEY_RIGHT) {
- event.type = Common::EVENT_RBUTTONDOWN;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
- if (getKeysReleased() & KEY_RIGHT) {
- event.type = Common::EVENT_RBUTTONUP;
- event.mouse = Common::Point(getPenX(), getPenY());
- system->addEvent(event);
- }
- }
+ else
+ {
+ doButtonSelectMode(system);
}
if (((!(getKeysHeld() & KEY_L)) && (!(getKeysHeld() & KEY_R)) || (indyFightState)) && (displayModeIs8Bit)) {
@@ -1537,8 +1709,8 @@ void triggerIcon(int imageNum) {
void setIcon(int num, int x, int y, int imageNum, int flags, bool enable) {
- sprites[num].attribute[0] = ATTR0_BMP | (enable? y: 192) | (!enable? ATTR0_DISABLED: 0);
- sprites[num].attribute[1] = ATTR1_SIZE_32 | x | flags;
+ sprites[num].attribute[0] = ATTR0_BMP | (enable? (y & 0xFF): 192) | (!enable? ATTR0_DISABLED: 0);
+ sprites[num].attribute[1] = ATTR1_SIZE_32 | (x & 0x1FF) | flags;
sprites[num].attribute[2] = ATTR2_ALPHA(1)| (imageNum * 16);
}
@@ -1552,28 +1724,30 @@ void updateStatus() {
int offs;
if (displayModeIs8Bit) {
- switch (mouseMode) {
- case MOUSE_LEFT: {
- offs = 1;
- break;
- }
- case MOUSE_RIGHT: {
- offs = 2;
- break;
- }
- case MOUSE_HOVER: {
- offs = 0;
- break;
- }
- default: {
- // Nothing!
- offs = 0;
- break;
+ if (!tapScreenClicks) {
+ switch (mouseMode) {
+ case MOUSE_LEFT: {
+ offs = 1;
+ break;
+ }
+ case MOUSE_RIGHT: {
+ offs = 2;
+ break;
+ }
+ case MOUSE_HOVER: {
+ offs = 0;
+ break;
+ }
+ default: {
+ // Nothing!
+ offs = 0;
+ break;
+ }
}
+
+ setIcon(0, 208, 150, offs, 0, true);
}
- setIcon(0, 208, 150, offs, 0, true);
-
if (indyFightState) {
setIcon(1, (190 - 32), 150, 3, (indyFightRight? 0: ATTR1_FLIP_X), true);
// consolePrintf("%d\n", indyFightRight);
@@ -1631,7 +1805,7 @@ void setMainScreenScroll(int x, int y) {
BG3_CX = x + (((frameCount & 1) == 0)? 64: 0);
BG3_CY = y;
- if (!gameScreenSwap) {
+ if ((!gameScreenSwap) || (touchPadStyle)) {
touchX = x >> 8;
touchY = y >> 8;
}
@@ -1660,7 +1834,7 @@ void setMainScreenScale(int x, int y) {
BG3_YDY = y;
}
- if (!gameScreenSwap) {
+ if ((!gameScreenSwap) || (touchPadStyle)) {
touchScX = x;
touchScY = y;
}
@@ -1676,7 +1850,7 @@ void setZoomedScreenScroll(int x, int y, bool shake) {
touchY = y >> 8;
} else */{
- if (gameScreenSwap) {
+ if ((gameScreenSwap) && (!touchPadStyle)) {
touchX = x >> 8;
touchY = y >> 8;
}
@@ -1696,7 +1870,7 @@ void setZoomedScreenScale(int x, int y) {
} else */{
- if (gameScreenSwap) {
+ if ((gameScreenSwap) && (!touchPadStyle)) {
touchScX = x;
touchScY = y;
}
@@ -1757,18 +1931,22 @@ void VBlankHandler(void) {
frameCount++;
- if ((cursorEnable) && (mouseCursorVisible))
- {
+ if ((cursorEnable) && (mouseCursorVisible)) {
if (!keyboardEnable) {
storedMouseX = penX;
storedMouseY = penY;
}
- setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
- }
- else
- {
+ if (gameScreenSwap) {
+ setIcon(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
+ setIconMain(3, 0, 0, 0, 0, false);
+ } else {
+ setIconMain(3, storedMouseX - mouseHotspotX, storedMouseY - mouseHotspotY, 8, 0, true);
+ setIcon(3, 0, 0, 0, 0, false);
+ }
+ } else {
setIconMain(3, 0, 0, 0, 0, false);
+ setIcon(3, 0, 0, 0, 0, false);
}
@@ -1826,7 +2004,7 @@ void VBlankHandler(void) {
SUB_BG3_YDX = 0;
SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/
- static int ratio = ( 320 << 8) / SCUMM_GAME_WIDTH;
+ static int ratio = (320 << 8) / SCUMM_GAME_WIDTH;
bool zooming = false;
@@ -1851,8 +2029,12 @@ void VBlankHandler(void) {
subScreenWidth = 256 >> 1;
subScreenHeight = 192 >> 1;
} else {
- subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8;
- subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8;
+// subScreenWidth = (((SCUMM_GAME_HEIGHT * 256) / 192) * subScreenScale) >> 8;
+// subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8;
+
+
+ subScreenWidth = (256 * subScreenScale) >> 8;
+ subScreenHeight = (192 * subScreenScale) >> 8;
if ( ((subScreenWidth) > 256 - 8) && ((subScreenWidth) < 256 + 8) ) {
subScreenWidth = 256;
@@ -2215,43 +2397,141 @@ void penUpdate() {
// if (getKeysHeld() & KEY_L) consolePrintf("%d, %d penX=%d, penY=%d tz=%d\n", IPC->touchXpx, IPC->touchYpx, penX, penY, IPC->touchZ1);
- if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me.
+ bool penDownThisFrame = (IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0);
+ bool firstFrame = penDownFrames == 2;
+ static bool moved = false;
- if ((penHeld)) {
- penHeld = true;
- penDown = false;
+ if ((tapScreenClicks) && (!getKeyboardEnable()) && (getIsDisplayMode8Bit())) {
- if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
- penX = IPC->touchXpx + touchXOffset;
- penY = IPC->touchYpx + touchYOffset;
+ if ((tapTimeout >= 0)) {
+ tapTimeout++;
+
+ if (((tapTimeout > 15) || (tapCount == 2)) && (tapCount > 0)) {
+ tapComplete = tapCount;
+ tapCount = 0;
+// consolePrintf("Taps: %d\n", tapComplete);
}
+ }
- } else {
- penDown = true;
- penHeld = true;
- penDownSaved = true;
+
- //if ( (ABS(penX - IPC->touchXpx) < 10) && (ABS(penY - IPC->touchYpx) < 10) ) {
- if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
- penX = IPC->touchXpx;
- penY = IPC->touchYpx;
+ if ((penHeld) && (!penDownThisFrame)) {
+ if ((touchPadStyle) || (moved) || (tapCount == 1)) {
+ if ((penDownFrames > 0) && (penDownFrames < 6) && ((tapTimeout == -1) || (tapTimeout > 2))) {
+ tapCount++;
+ tapTimeout = 0;
+// consolePrintf("Tap! %d\n", penDownFrames);
+ moved = false;
+ }
}
- //}
}
+ }
- } else {
- if (penHeld) {
- penReleased = true;
- penReleasedSaved = true;
+
+
+ if ((touchPadStyle) && (getIsDisplayMode8Bit())) {
+
+ if ((penDownFrames > 0)) {
+
+
+ if ((penHeld)) {
+
+ if (penDownThisFrame)
+ {
+ if (penDownFrames >= 2) {
+ int diffX = IPC->touchXpx - penDownX;
+ int diffY = IPC->touchYpx - penDownY;
+
+ int speed = ABS(diffX) + ABS(diffY);
+
+ if ((ABS(diffX) < 35) && (ABS(diffY) < 35))
+ {
+
+ if (speed >= 8)
+ {
+ diffX *= ((speed >> 3) * touchPadSensitivity) >> 3;
+ diffY *= ((speed >> 3) * touchPadSensitivity) >> 3;
+ }
+
+ penX += diffX;
+ penY += diffY;
+ if (penX > 255) penX = 255;
+ if (penX < 0) penX = 0;
+ if (penY > 191) penY = 191;
+ if (penY < 0) penY = 0;
+ }
+
+// consolePrintf("x: %d y: %d\n", IPC->touchYpx - penDownY, IPC->touchYpx - penDownY);
+ penDownX = IPC->touchXpx;
+ penDownY = IPC->touchYpx;
+
+ }
+ }
+ else
+ {
+ }
+
+
+ } else {
+ penDown = true;
+ penHeld = true;
+ penDownSaved = true;
+
+ // First frame, so save pen positions
+ if (penDownThisFrame) {
+ penDownX = IPC->touchXpx;
+ penDownY = IPC->touchYpx;
+ }
+ }
+
} else {
- penReleased = false;
+ if (penHeld) {
+ penReleased = true;
+ penReleasedSaved = true;
+ } else {
+ penReleased = false;
+ }
+
+ penDown = false;
+ penHeld = false;
}
+ } else {
+ if ((penDownFrames > 1)) { // Is this right? Dunno, but it works for me.
+
+ if ((penHeld)) {
+ penHeld = true;
+ penDown = false;
+ } else {
+ penDown = true;
+ penHeld = true;
+ penDownSaved = true;
+ }
+
+ if ((IPC->touchZ1 > 0) && (IPC->touchXpx > 0) && (IPC->touchYpx > 0)) {
+ penX = IPC->touchXpx + touchXOffset;
+ penY = IPC->touchYpx + touchYOffset;
+ moved = true;
+ }
+
- penDown = false;
- penHeld = false;
+
+ } else {
+ if (penHeld) {
+ penReleased = true;
+ penReleasedSaved = true;
+ } else {
+ penReleased = false;
+ }
+
+ penDown = false;
+ penHeld = false;
+ }
+
+
}
+
if ((IPC->touchZ1 > 0) || ((penDownFrames == 2)) ) {
penDownLastFrame = true;
penDownFrames++;
@@ -2259,7 +2539,6 @@ void penUpdate() {
penDownLastFrame = false;
penDownFrames = 0;
}
-
}
int leftHandedSwap(int keys) {
@@ -2346,8 +2625,7 @@ int getPenX() {
int x = ((penX * touchScX) >> 8) + touchX;
x = x < 0? 0: (x > gameWidth - 1? gameWidth - 1: x);
- if (snapToBorder)
- {
+ if (snapToBorder) {
if (x < 8) x = 0;
if (x > gameWidth - 8) x = gameWidth - 1;
}
@@ -2359,8 +2637,7 @@ int getPenY() {
int y = ((penY * touchScY) >> 8) + touchY;
y = y < 0? 0: (y > gameHeight - 1? gameHeight - 1: y);
- if (snapToBorder)
- {
+ if (snapToBorder) {
if (y < 8) y = 0;
if (y > gameHeight - 8) y = gameHeight - 1;
}
@@ -2377,6 +2654,8 @@ GLvector getPenPos() {
return v;
}
+#ifdef GBA_SRAM_SAVE
+
void formatSramOption() {
consolePrintf("The following files are present in save RAM:\n");
DSSaveFileManager::instance()->listFiles();
@@ -2398,7 +2677,7 @@ void formatSramOption() {
}
}
}
-
+#endif
void setIndyFightState(bool st) {
indyFightState = st;
@@ -2496,8 +2775,6 @@ struct cardTranslate {
char dldiId[5];
};
-#define NUM_CARD_READERS 7
-
cardTranslate cardReaderTable[] = {
{DEVICE_TYPE_M3SD, DEVICE_M3SD, "M3SD"},
{DEVICE_TYPE_M3CF, DEVICE_M3CF, "M3CF"},
@@ -2519,13 +2796,13 @@ void reboot() {
consolePrintf("DLDI Device ID: %s\n", id);
- for (int r = 0; r < NUM_CARD_READERS; r++) {
+ for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) {
if (!stricmp(id, cardReaderTable[r].dldiId)) {
deviceType = cardReaderTable[r].cartResetId;
}
}
} else {
- for (int r = 0; r < NUM_CARD_READERS; r++) {
+ for (int r = 0; r < ARRAYSIZE(cardReaderTable); r++) {
if (disc_getDeviceId() == cardReaderTable[r].svmId) {
deviceType = cardReaderTable[r].cartResetId;
}
@@ -2573,13 +2850,66 @@ void powerOff() {
/////////////////
-int main(void)
-{
+
+void dsExceptionHandler() {
+ consolePrintf("Blue screen of death");
+ setExceptionHandler(NULL);
+
+
+ u32 currentMode = getCPSR() & 0x1f;
+ u32 thumbState = ((*(u32*)0x027FFD90) & 0x20);
+
+ u32 codeAddress, exceptionAddress = 0;
+
+ int offset = 8;
+
+ if ( currentMode == 0x17 ) {
+ consolePrintf("\x1b[10Cdata abort!\n\n");
+ codeAddress = exceptionRegisters[15] - offset;
+ if ( (codeAddress > 0x02000000 && codeAddress < 0x02400000) ||
+ (codeAddress > (u32)__itcm_start && codeAddress < (u32)(__itcm_start + 32768)) )
+ exceptionAddress = getExceptionAddress( codeAddress, thumbState);
+ else
+ exceptionAddress = codeAddress;
+
+ } else {
+ if (thumbState)
+ offset = 2;
+ else
+ offset = 4;
+ consolePrintf("\x1b[5Cundefined instruction!\n\n");
+ codeAddress = exceptionRegisters[15] - offset;
+ exceptionAddress = codeAddress;
+ }
+
+ consolePrintf(" pc: %08X addr: %08X\n\n",codeAddress,exceptionAddress);
+
+ int i;
+ for ( i=0; i < 8; i++ ) {
+ consolePrintf( " %s: %08X %s: %08X\n",
+ registerNames[i], exceptionRegisters[i],
+ registerNames[i+8],exceptionRegisters[i+8]);
+ }
+// u32 *stack = (u32 *)exceptionRegisters[13];
+// for ( i=0; i<10; i++ ) {
+// consolePrintf( "\x1b[%d;2H%08X: %08X %08X", i + 14, (u32)&stack[i*2],stack[i*2], stack[(i*2)+1] );
+// }
+
+ memoryReport();
+
+ while(1);
+}
+
+
+
+
+int main(void) {
soundCallback = NULL;
initHardware();
+ setExceptionHandler(dsExceptionHandler);
#ifdef USE_DEBUGGER
for (int r = 0; r < 150; r++) {
@@ -2663,36 +2993,33 @@ int main(void)
consolePrintf("-------------------------------\n");
consolePrintf("ScummVM DS\n");
consolePrintf("Ported by Neil Millstone\n");
- consolePrintf("Version 0.11.1 beta2");
+ consolePrintf("Version 0.13.0 SVN ");
#if defined(DS_BUILD_A)
consolePrintf("build A\n");
consolePrintf("Lucasarts SCUMM games (SCUMM)\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_B)
consolePrintf("build B\n");
consolePrintf("BASS, QUEEN\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_C)
consolePrintf("build C\n");
consolePrintf("Simon/Elvira/Waxworks (AGOS)\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_D)
consolePrintf("build D\n");
consolePrintf("AGI, CINE, GOB\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_E)
consolePrintf("build E\n");
consolePrintf("Inherit the Earth (SAGA)\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_F)
consolePrintf("build F\n");
consolePrintf("The Legend of Kyrandia (KYRA)\n");
- consolePrintf("-------------------------------\n");
#elif defined(DS_BUILD_G)
- consolePrintf("build F\n");
- consolePrintf("Lure of the Temptress (LURE)\n");
- consolePrintf("-------------------------------\n");
+ consolePrintf("build G\n");
+ consolePrintf("Lure of the Tempress (LURE)\n");
+#elif defined(DS_BUILD_H)
+ consolePrintf("build H\n");
+ consolePrintf("Nippon Safes (PARALLATION)\n");
#endif
+ consolePrintf("-------------------------------\n");
consolePrintf("L/R + D-pad/pen: Scroll view\n");
consolePrintf("D-pad left: Left mouse button\n");
consolePrintf("D-pad right: Right mouse button\n");
@@ -2808,9 +3135,11 @@ int main(void)
g_system = new OSystem_DS();
assert(g_system);
+#ifdef GBA_SRAM_SAVE
if ((keysHeld() & KEY_L) && (keysHeld() & KEY_R)) {
formatSramOption();
}
+#endif
IPC->adpcm.semaphore = false;
@@ -2831,6 +3160,8 @@ int main(void)
const char *argv[] = {"/scummvmds", "--config=scummvmf.ini"};
#elif defined(DS_BUILD_G)
const char *argv[] = {"/scummvmds", "--config=scummvmg.ini"};
+#elif defined(DS_BUILD_H)
+ const char *argv[] = {"/scummvmds", "--config=scummvmh.ini"};
#endif
while (1) {
diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h
index 43258b5c5d..ab74554917 100644
--- a/backends/platform/ds/arm9/source/dsmain.h
+++ b/backends/platform/ds/arm9/source/dsmain.h
@@ -38,7 +38,8 @@ enum controlType {
CONT_SIMON,
CONT_FUTURE_WARS,
CONT_AGI,
- CONT_GOBLINS
+ CONT_GOBLINS,
+ CONT_NIPPON,
};
struct gameListType {
@@ -56,6 +57,7 @@ int getPenX();
int getPenY();
GLvector getPenPos();
void consumePenEvents();
+controlType getControlType();
// Pad reading
int getKeysHeld();
@@ -64,6 +66,8 @@ int getKeysDown();
int getKeysReleased();
void consumeKeys();
int leftHandedSwap(int keys);
+void setGameScreenSwap(bool enable);
+void setSensitivity(int sensitivity);
// Video
void displayMode8Bit(); // Switch to 8-bit mode5
@@ -81,6 +85,7 @@ u16* getScalerBuffer();
void setTalkPos(int x, int y);
void setTopScreenTarget(int x, int y);
void set200PercentFixedScale(bool on);
+void setTopScreenZoom(int percentage);
// Timers
void setTimerCallback(OSystem_DS::TimerProc proc, int interval); // Setup a callback function at a regular interval
@@ -88,7 +93,9 @@ int getMillis(); // Return the current runtime in milliseconds
void doTimerCallback(); // Call callback function if required
// Sound
-void doSoundCallback(); // Call function if sound buffers need more data
+void doSoundCallback();
+void startSound(int freq, int buffer); // Start sound hardware
+// Call function if sound buffers need more data
void playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050); // Start a sound
void stopSound(int channel);
int getSoundFrequency();
@@ -131,6 +138,8 @@ void setIndyFightState(bool st);
bool getIndyFightState();
bool isCpuScalerEnabled();
void setCpuScalerEnable(bool enable);
+void setTrackPadStyleEnable(bool enable);
+void setTapScreenClicksEnable(bool enable);
// Display
bool getIsDisplayMode8Bit();
diff --git a/backends/platform/ds/arm9/source/dsoptions.cpp b/backends/platform/ds/arm9/source/dsoptions.cpp
index edb9c70580..2dbc4b842b 100644
--- a/backends/platform/ds/arm9/source/dsoptions.cpp
+++ b/backends/platform/ds/arm9/source/dsoptions.cpp
@@ -25,6 +25,7 @@
#include "gui/dialog.h"
#include "gui/newgui.h"
#include "gui/ListWidget.h"
+#include "gui/TabWidget.h"
#include "osystem_ds.h"
#include "engines/scumm/scumm.h"
#include "touchkeyboard.h"
@@ -41,8 +42,67 @@ namespace Scumm {
namespace DS {
-DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) {
- addButton(this, 10, 175, "Close", GUI::kCloseCmd, 'C');
+DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(0, 0, 320 - 10, 230 - 40) {
+
+ addButton(this, 10, 170, "Close", GUI::kCloseCmd, 'C');
+ _tab = new GUI::TabWidget(this, 5, 5, 300, 230 - 20 - 40 - 10);
+
+ _tab->addTab("Controls");
+
+ _leftHandedCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 130, 20, "Left handed mode", 0, 'L');
+ _indyFightCheckbox = new GUI::CheckboxWidget(_tab, 5, 20, 140, 20, "Indy fight controls", 0, 'I');
+ _showCursorCheckbox = new GUI::CheckboxWidget(_tab, 150, 5, 130, 20, "Show mouse cursor", 0, 'T');
+ _snapToBorderCheckbox = new GUI::CheckboxWidget(_tab, 150, 20, 130, 20, "Snap to edges", 0, 'T');
+
+ new GUI::StaticTextWidget(_tab, 20, 35, 100, 15, "Touch X Offset", GUI::kTextAlignLeft);
+ _touchX = new GUI::SliderWidget(_tab, 130, 35, 130, 12, 1);
+ _touchX->setMinValue(-8);
+ _touchX->setMaxValue(+8);
+ _touchX->setValue(0);
+ _touchX->setFlags(GUI::WIDGET_CLEARBG);
+
+ new GUI::StaticTextWidget(_tab, 20, 50, 100, 15, "Touch Y Offset", GUI::kTextAlignLeft);
+ _touchY = new GUI::SliderWidget(_tab, 130, 50, 130, 12, 2);
+ _touchY->setMinValue(-8);
+ _touchY->setMaxValue(+8);
+ _touchY->setValue(0);
+ _touchY->setFlags(GUI::WIDGET_CLEARBG);
+
+ new GUI::StaticTextWidget(_tab, 130 + 65 - 10, 65, 20, 15, "0", GUI::kTextAlignCenter);
+ new GUI::StaticTextWidget(_tab, 130 + 130 - 10, 65, 20, 15, "8", GUI::kTextAlignCenter);
+ new GUI::StaticTextWidget(_tab, 130 - 20, 65, 20, 15, "-8", GUI::kTextAlignCenter);
+
+
+ _touchPadStyle = new GUI::CheckboxWidget(_tab, 5, 80, 270, 20, "Use laptop trackpad-style cursor control", 0x20000001, 'T');
+ _screenTaps = new GUI::CheckboxWidget(_tab, 5, 95, 285, 20, "Tap for left click, double tap right click", 0x20000002, 'T');
+
+ _sensitivityLabel = new GUI::StaticTextWidget(_tab, 20, 110, 110, 15, "Sensitivity", GUI::kTextAlignLeft);
+ _sensitivity = new GUI::SliderWidget(_tab, 130, 110, 130, 12, 1);
+ _sensitivity->setMinValue(4);
+ _sensitivity->setMaxValue(16);
+ _sensitivity->setValue(8);
+ _sensitivity->setFlags(GUI::WIDGET_CLEARBG);
+
+ _tab->addTab("Graphics");
+
+ new GUI::StaticTextWidget(_tab, 5, 70, 180, 15, "Initial top screen scale:", GUI::kTextAlignLeft);
+
+ _100PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 85, 230, 20, "100%", 0x30000001, 'T');
+ _150PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 100, 230, 20, "150%", 0x30000002, 'T');
+ _200PercentCheckbox = new GUI::CheckboxWidget(_tab, 5, 115, 230, 20, "200%", 0x30000003, 'T');
+
+ new GUI::StaticTextWidget(_tab, 5, 5, 180, 15, "Main screen scaling:", GUI::kTextAlignLeft);
+
+ _hardScaler = new GUI::CheckboxWidget(_tab, 5, 20, 270, 20, "Hardware scale (fast, but low quality)", 0x10000001, 'T');
+ _cpuScaler = new GUI::CheckboxWidget(_tab, 5, 35, 270, 20, "Software scale (good quality, but slower)", 0x10000002, 'S');
+ _unscaledCheckbox = new GUI::CheckboxWidget(_tab, 5, 50, 270, 20, "Unscaled (you must scroll left and right)", 0x10000003, 'S');
+
+ _tab->addTab("General");
+
+ _highQualityAudioCheckbox = new GUI::CheckboxWidget(_tab, 5, 5, 250, 20, "High quality audio (slower) (reboot)", 0, 'T');
+ _disablePowerOff = new GUI::CheckboxWidget(_tab, 5, 20, 200, 20, "Disable power off", 0, 'T');
+
+ _tab->setActiveTab(0);
_radioButtonMode = false;
@@ -52,46 +112,17 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) {
}
#endif
- new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter);
+// new GUI::StaticTextWidget(this, 90, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter);
- _leftHandedCheckbox = new GUI::CheckboxWidget(this, 5, 70, 130, 20, "Left handed mode", 0, 'L');
- _indyFightCheckbox = new GUI::CheckboxWidget(this, 5, 40, 200, 20, "Indy fighting controls", 0, 'I');
- _twoHundredPercentCheckbox = new GUI::CheckboxWidget(this, 5, 55, 230, 20, "Zoomed screen at fixed 200% zoom", 0, 'T');
- _highQualityAudioCheckbox = new GUI::CheckboxWidget(this, 5, 25, 250, 20, "High quality audio (slower) (reboot)", 0, 'T');
- _disablePowerOff = new GUI::CheckboxWidget(this, 5, 85, 130, 20, "Disable power off", 0, 'T');
- _showCursorCheckbox = new GUI::CheckboxWidget(this, 5, 100, 130, 20, "Show mouse cursor", 0, 'T');
//#ifdef ALLOW_CPU_SCALER
// _cpuScaler = new GUI::CheckboxWidget(this, 160, 115, 90, 20, "CPU scaler", 0, 'T');
//#endif
- new GUI::StaticTextWidget(this, 180, 70, 130, 15, "Main screen:", GUI::kTextAlignLeft);
-
- _hardScaler = new GUI::CheckboxWidget(this, 140, 85, 170, 20, "Hardware scale (fast)", 0x10000001, 'T');
- _cpuScaler = new GUI::CheckboxWidget(this, 140, 100, 170, 20, "Software scale (quality)", 0x10000002, 'S');
- _unscaledCheckbox = new GUI::CheckboxWidget(this, 140, 115, 170, 20, "Unscaled", 0x10000003, 'S');
- _snapToBorderCheckbox = new GUI::CheckboxWidget(this, 5, 115, 120, 20, "Snap to border", 0, 'T');
- new GUI::StaticTextWidget(this, 20, 145, 110, 15, "Touch X Offset", GUI::kTextAlignLeft);
- _touchX = new GUI::SliderWidget(this, 130, 145, 130, 12, 1);
- _touchX->setMinValue(-8);
- _touchX->setMaxValue(+8);
- _touchX->setValue(0);
- _touchX->setFlags(GUI::WIDGET_CLEARBG);
-
- new GUI::StaticTextWidget(this, 20, 160, 110, 15, "Touch Y Offset", GUI::kTextAlignLeft);
- _touchY = new GUI::SliderWidget(this, 130, 160, 130, 12, 2);
- _touchY->setMinValue(-8);
- _touchY->setMaxValue(+8);
- _touchY->setValue(0);
- _touchY->setFlags(GUI::WIDGET_CLEARBG);
-
- new GUI::StaticTextWidget(this, 130 + 65 - 10, 175, 20, 15, "0", GUI::kTextAlignCenter);
- new GUI::StaticTextWidget(this, 130 + 130 - 10, 175, 20, 15, "8", GUI::kTextAlignCenter);
- new GUI::StaticTextWidget(this, 130 - 10, 175, 20, 15, "-8", GUI::kTextAlignCenter);
#ifdef DS_SCUMM_BUILD
_delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm);
@@ -125,10 +156,36 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) {
_unscaledCheckbox->setState(false);
}
- if (ConfMan.hasKey("twohundredpercent", "ds")) {
- _twoHundredPercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds"));
+
+ if (ConfMan.hasKey("topscreenzoom", "ds")) {
+
+ _100PercentCheckbox->setState(false);
+ _150PercentCheckbox->setState(false);
+ _200PercentCheckbox->setState(false);
+
+ switch (ConfMan.getInt("topscreenzoom", "ds"))
+ {
+ case 100: {
+ _100PercentCheckbox->setState(true);
+ break;
+ }
+
+ case 150: {
+ _150PercentCheckbox->setState(true);
+ break;
+ }
+
+ case 200: {
+ _200PercentCheckbox->setState(true);
+ break;
+ }
+ }
+
+ } else if (ConfMan.hasKey("twohundredpercent", "ds")) {
+ _200PercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds"));
} else {
- _twoHundredPercentCheckbox->setState(false);
+ // No setting
+ _150PercentCheckbox->setState(true);
}
if (ConfMan.hasKey("22khzaudio", "ds")) {
@@ -165,6 +222,29 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(5, 0, 320 - 5, 230 - 20) {
_touchY->setValue(0);
}
+ if (ConfMan.hasKey("sensitivity", "ds")) {
+ _sensitivity->setValue(ConfMan.getInt("sensitivity", "ds"));
+ } else {
+ _sensitivity->setValue(8);
+ }
+
+ if (ConfMan.hasKey("touchpad", "ds")) {
+ _touchPadStyle->setState(ConfMan.getBool("touchpad", "ds"));
+ } else {
+ _touchPadStyle->setState(0);
+ }
+
+ if (ConfMan.hasKey("screentaps", "ds")) {
+ _screenTaps->setState(ConfMan.getBool("screentaps", "ds"));
+ } else {
+ _screenTaps->setState(0);
+ }
+
+ _screenTaps->setEnabled(!_touchPadStyle->getState());
+ _sensitivity->setEnabled(_touchPadStyle->getState());
+ _sensitivityLabel->setEnabled(_touchPadStyle->getState());
+ _sensitivityLabel->draw();
+
if (!_cpuScaler->getState() && !_unscaledCheckbox->getState()) {
_hardScaler->setState(true);
}
@@ -180,7 +260,7 @@ DSOptionsDialog::~DSOptionsDialog() {
void DSOptionsDialog::updateConfigManager() {
ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds");
ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds");
- ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds");
+// ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds");
ConfMan.setBool("22khzaudio", _highQualityAudioCheckbox->getState(), "ds");
ConfMan.setBool("disablepoweroff", _disablePowerOff->getState(), "ds");
#ifdef ALLOW_CPU_SCALER
@@ -190,6 +270,24 @@ void DSOptionsDialog::updateConfigManager() {
ConfMan.setInt("yoffset", _touchY->getValue(), "ds");
ConfMan.setBool("showcursor", _showCursorCheckbox->getState(), "ds");
ConfMan.setBool("snaptoborder", _snapToBorderCheckbox->getState(), "ds");
+ ConfMan.setBool("touchpad", _touchPadStyle->getState(), "ds");
+ ConfMan.setBool("screentaps", _screenTaps->getState(), "ds");
+ ConfMan.setInt("sensitivity", _sensitivity->getValue(), "ds");
+
+ u32 zoomLevel = 150;
+
+ if (_100PercentCheckbox->getState()) {
+ zoomLevel = 100;
+ } else if (_150PercentCheckbox->getState()) {
+ zoomLevel = 150;
+ } else if (_200PercentCheckbox->getState()) {
+ zoomLevel = 200;
+ }
+
+ consolePrintf("Saved zoom: %d\n", zoomLevel);
+
+ ConfMan.setInt("topscreenzoom", zoomLevel, "ds");
+
DS::setOptions();
}
@@ -227,6 +325,70 @@ void DSOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint
}
+ if ((!guard) && (_radioButtonMode))
+ {
+ guard = true;
+
+ if ((sender == _touchPadStyle) && (cmd == 0x20000001)) {
+
+ if (_touchPadStyle->getState()) {
+ // Swap screens when turning on trackpad style, it feels
+ // much more natural!
+ DS::setGameScreenSwap(true);
+
+ _screenTaps->setState(true);
+ _screenTaps->setEnabled(false);
+ _screenTaps->draw();
+ _sensitivity->setEnabled(true);
+ _sensitivityLabel->setEnabled(true);
+ _sensitivityLabel->draw();
+ _sensitivity->draw();
+ } else {
+ DS::setGameScreenSwap(false);
+
+ _screenTaps->setEnabled(true);
+ _screenTaps->setState(false);
+ _screenTaps->draw();
+ _sensitivity->setEnabled(false);
+ _sensitivityLabel->setEnabled(false);
+ _sensitivityLabel->draw();
+ _sensitivity->draw();
+ }
+ }
+
+ guard = false;
+ }
+
+ if ((!guard) && (_radioButtonMode)) {
+
+ guard = true;
+
+ if (cmd == 0x30000001) {
+ _100PercentCheckbox->setState(true);
+ _150PercentCheckbox->setState(false);
+ _200PercentCheckbox->setState(false);
+ DS::setTopScreenZoom(100);
+ }
+
+ if (cmd == 0x30000002) {
+ _100PercentCheckbox->setState(false);
+ _150PercentCheckbox->setState(true);
+ _200PercentCheckbox->setState(false);
+ DS::setTopScreenZoom(150);
+ }
+
+ if (cmd == 0x30000003) {
+ _100PercentCheckbox->setState(false);
+ _150PercentCheckbox->setState(false);
+ _200PercentCheckbox->setState(true);
+ DS::setTopScreenZoom(200);
+ }
+
+ guard = false;
+
+ }
+
+
if (cmd == GUI::kCloseCmd) {
updateConfigManager();
close();
@@ -297,6 +459,8 @@ void showOptionsDialog() {
}
void setOptions() {
+ static bool firstLoad = true;
+
ConfMan.addGameDomain("ds");
if (ConfMan.hasKey("lefthanded", "ds")) {
@@ -327,10 +491,16 @@ void setOptions() {
DS::setUnscaledMode(false);
}
- if (ConfMan.hasKey("twohundredpercent", "ds")) {
- DS::set200PercentFixedScale(ConfMan.getBool("twohundredpercent", "ds"));
- } else {
- DS::set200PercentFixedScale(false);
+ if (firstLoad) {
+ if (ConfMan.hasKey("topscreenzoom", "ds")) {
+ DS::setTopScreenZoom(ConfMan.getInt("topscreenzoom", "ds"));
+ } else {
+ if (ConfMan.hasKey("twohundredpercent", "ds")) {
+ DS::setTopScreenZoom(200);
+ } else {
+ DS::setTopScreenZoom(150);
+ }
+ }
}
if (ConfMan.hasKey("xoffset", "ds")) {
@@ -345,6 +515,12 @@ void setOptions() {
DS::setTouchXOffset(0);
}
+ if (ConfMan.hasKey("sensitivity", "ds")) {
+ DS::setSensitivity(ConfMan.getInt("sensitivity", "ds"));
+ } else {
+ DS::setSensitivity(8);
+ }
+
#ifdef ALLOW_CPU_SCALER
if (ConfMan.hasKey("cpu_scaler", "ds")) {
DS::setCpuScalerEnable(ConfMan.getBool("cpu_scaler", "ds"));
@@ -353,6 +529,33 @@ void setOptions() {
}
#endif
+ if (ConfMan.hasKey("screentaps", "ds")) {
+ DS::setTapScreenClicksEnable(ConfMan.getBool("screentaps", "ds"));
+ } else {
+ DS::setTapScreenClicksEnable(false);
+ }
+
+ if (ConfMan.hasKey("touchpad", "ds")) {
+ bool enable = ConfMan.getBool("touchpad", "ds");
+
+ DS::setTrackPadStyleEnable(enable);
+
+ if ((enable) and (firstLoad)) {
+ // If we've just booted up, want to swap screens when trackpad mode is in use
+ // but not every time we enter the options dialog.
+ DS::setGameScreenSwap(true);
+ }
+
+ if (enable) {
+ DS::setTapScreenClicksEnable(true);
+ }
+
+ } else {
+ DS::setTrackPadStyleEnable(false);
+ }
+
+
+ firstLoad = false;
}
}
diff --git a/backends/platform/ds/arm9/source/dsoptions.h b/backends/platform/ds/arm9/source/dsoptions.h
index 9cfa785ca8..e3ab2f55e0 100644
--- a/backends/platform/ds/arm9/source/dsoptions.h
+++ b/backends/platform/ds/arm9/source/dsoptions.h
@@ -30,6 +30,7 @@
#include "gui/object.h"
#include "gui/widget.h"
#include "gui/dialog.h"
+#include "gui/TabWidget.h"
#include "scumm/dialogs.h"
namespace DS {
@@ -45,11 +46,18 @@ protected:
void togglePause();
void updateConfigManager();
+ GUI::TabWidget* _tab;
+
+ GUI::StaticTextWidget* _sensitivityLabel;
+
GUI::SliderWidget* _touchX;
GUI::SliderWidget* _touchY;
+ GUI::SliderWidget* _sensitivity;
GUI::CheckboxWidget* _leftHandedCheckbox;
GUI::CheckboxWidget* _unscaledCheckbox;
- GUI::CheckboxWidget* _twoHundredPercentCheckbox;
+ GUI::CheckboxWidget* _100PercentCheckbox;
+ GUI::CheckboxWidget* _150PercentCheckbox;
+ GUI::CheckboxWidget* _200PercentCheckbox;
GUI::CheckboxWidget* _indyFightCheckbox;
GUI::CheckboxWidget* _highQualityAudioCheckbox;
GUI::CheckboxWidget* _disablePowerOff;
@@ -59,6 +67,9 @@ protected:
GUI::CheckboxWidget* _hardScaler;
GUI::CheckboxWidget* _cpuScaler;
+ GUI::CheckboxWidget* _touchPadStyle;
+ GUI::CheckboxWidget* _screenTaps;
+
#ifdef DS_SCUMM_BUILD
Scumm::SaveLoadChooser* _delDialog;
#endif
diff --git a/backends/platform/ds/arm9/source/gbampsave.cpp b/backends/platform/ds/arm9/source/gbampsave.cpp
index 9c8af81a6e..a53ab9739d 100644
--- a/backends/platform/ds/arm9/source/gbampsave.cpp
+++ b/backends/platform/ds/arm9/source/gbampsave.cpp
@@ -54,8 +54,8 @@ bool GBAMPSaveFile::eos() const {
return DS::std_feof(handle);
}
-void GBAMPSaveFile::skip(uint32 bytes) {
- DS::std_fseek(handle, bytes, SEEK_CUR);
+bool GBAMPSaveFile::skip(uint32 bytes) {
+ return DS::std_fseek(handle, bytes, SEEK_CUR) == 0;
}
void GBAMPSaveFile::flushSaveBuffer() {
@@ -67,11 +67,11 @@ void GBAMPSaveFile::flushSaveBuffer() {
}
}
-uint32 GBAMPSaveFile::pos() const {
+int32 GBAMPSaveFile::pos() const {
return DS::std_ftell(handle);
}
-uint32 GBAMPSaveFile::size() const {
+int32 GBAMPSaveFile::size() const {
int position = pos();
DS::std_fseek(handle, 0, SEEK_END);
int size = DS::std_ftell(handle);
@@ -79,8 +79,8 @@ uint32 GBAMPSaveFile::size() const {
return size;
}
-void GBAMPSaveFile::seek(int32 pos, int whence) {
- DS::std_fseek(handle, pos, whence);
+bool GBAMPSaveFile::seek(int32 pos, int whence) {
+ return DS::std_fseek(handle, pos, whence) == 0;
}
@@ -155,11 +155,13 @@ GBAMPSaveFile* GBAMPSaveFileManager::openSavefile(char const* name, bool saveOrL
sprintf(fileSpec, "%s/%s", getSavePath(), name);
}
-// consolePrintf(fileSpec);
+// consolePrintf("Opening the file: %s\n", fileSpec);
GBAMPSaveFile* sf = new GBAMPSaveFile(fileSpec, saveOrLoad);
if (sf->isOpen()) {
+// consolePrintf("Ok");
return sf;
} else {
+// consolePrintf("Fail");
delete sf;
return NULL;
}
@@ -192,8 +194,29 @@ Common::StringList GBAMPSaveFileManager::listSavefiles(const char *pattern) {
enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
char name[256];
- DS::std_cwd((char*)getSavePath()); //TODO : Check this suspicious const-cast
-// consolePrintf("Save path: '%s', pattern: '%s'\n", getSavePath(),pattern);
+ {
+ char dir[128];
+ strcpy(dir, getSavePath());
+ char *realName = dir;
+
+ if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) {
+ realName += 4;
+ }
+
+ // consolePrintf("Real cwd:%d\n", realName);
+
+ char* p = realName;
+ while (*p) {
+ if (*p == '\\') *p = '/';
+ p++;
+ }
+
+ // consolePrintf("Real cwd:%d\n", realName);
+ FAT_chdir(realName);
+
+ }
+
+// consolePrintf("Save path: '%s', pattern: '%s'\n", getSavePath(), pattern);
int fileType = FAT_FindFirstFileLFN(name);
@@ -206,7 +229,7 @@ Common::StringList GBAMPSaveFileManager::listSavefiles(const char *pattern) {
FAT_GetLongFilename(name);
- for (int r = 0; r < strlen(name); r++) {
+ for (int r = 0; name[r] != 0; r++) {
name[r] = tolower(name[r]);
}
diff --git a/backends/platform/ds/arm9/source/gbampsave.h b/backends/platform/ds/arm9/source/gbampsave.h
index d0cbc68bfd..6ddc4fd964 100644
--- a/backends/platform/ds/arm9/source/gbampsave.h
+++ b/backends/platform/ds/arm9/source/gbampsave.h
@@ -43,11 +43,11 @@ public:
virtual uint32 write(const void *buf, uint32 size);
virtual bool eos() const;
- virtual void skip(uint32 bytes);
+ virtual bool skip(uint32 bytes);
- virtual uint32 pos() const;
- virtual uint32 size() const;
- virtual void seek(int32 pos, int whence);
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ virtual bool seek(int32 pos, int whence);
void flushSaveBuffer();
diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp
index 79b0c5390b..5ddcb50b15 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.cpp
+++ b/backends/platform/ds/arm9/source/osystem_ds.cpp
@@ -41,7 +41,8 @@
OSystem_DS* OSystem_DS::_instance = NULL;
OSystem_DS::OSystem_DS()
- : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false)
+ : eventNum(0), lastPenFrame(0), queuePos(0), _mixer(NULL), _timer(NULL), _frameBufferExists(false),
+ _disableCursorPalette(true), _graphicsEnable(true)
{
// eventNum = 0;
// lastPenFrame = 0;
@@ -71,7 +72,13 @@ void OSystem_DS::initBackend() {
_timer = new DSTimerManager();
DS::setTimerCallback(&OSystem_DS::timerHandler, 10);
- _mixer->setOutputRate(11025 /*DS::getSoundFrequency()*/);
+ if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) {
+ DS::startSound(22050, 8192);
+ } else {
+ DS::startSound(11025, 4096);
+ }
+
+ _mixer->setOutputRate(DS::getSoundFrequency());
_mixer->setReady(true);
OSystem::initBackend();
@@ -79,7 +86,7 @@ void OSystem_DS::initBackend() {
bool OSystem_DS::hasFeature(Feature f) {
// consolePrintf("hasfeature\n");
- return (f == kFeatureVirtualKeyboard);
+ return (f == kFeatureVirtualKeyboard) || (f == kFeatureCursorHasPalette);
}
void OSystem_DS::setFeatureState(Feature f, bool enable) {
@@ -107,7 +114,7 @@ bool OSystem_DS::setGraphicsMode(int mode) {
}
bool OSystem_DS::setGraphicsMode(const char *name) {
-// consolePrintf("Set gfx mode %s\n", name);
+ consolePrintf("Set gfx mode %s\n", name);
return true;
}
@@ -116,8 +123,15 @@ int OSystem_DS::getGraphicsMode() const {
}
void OSystem_DS::initSize(uint width, uint height) {
-// consolePrintf("Set gfx mode %d x %d\n", width, height);
- DS::setGameSize(width, height);
+ // For Lost in Time, the title screen is displayed in 640x400.
+ // In order to support this game, the screen mode is set, but
+ // all draw calls are ignored until the game switches to 320x200.
+ if ((width == 640) && (height == 400)) {
+ _graphicsEnable = false;
+ } else {
+ _graphicsEnable = true;
+ DS::setGameSize(width, height);
+ }
}
int16 OSystem_DS::getHeight() {
@@ -129,9 +143,8 @@ int16 OSystem_DS::getWidth() {
}
void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
-// consolePrintf("Set palette %d, %d colours\n", start, num);
-//return;
- if (!DS::getIsDisplayMode8Bit()) return;
+// consolePrintf("Setpal %d, %d\n", start, num);
+
for (unsigned int r = start; r < start + num; r++) {
int red = *colors;
int green = *(colors + 1);
@@ -141,17 +154,44 @@ void OSystem_DS::setPalette(const byte *colors, uint start, uint num) {
green >>= 3;
blue >>= 3;
- if (r != 255)
+// if (r != 255)
{
- BG_PALETTE[r] = red | (green << 5) | (blue << 10);
- if (!DS::getKeyboardEnable()) {
- BG_PALETTE_SUB[r] = red | (green << 5) | (blue << 10);
+ u16 paletteValue = red | (green << 5) | (blue << 10);
+
+ if (DS::getIsDisplayMode8Bit()) {
+ BG_PALETTE[r] = paletteValue;
+ if (!DS::getKeyboardEnable()) {
+ BG_PALETTE_SUB[r] = paletteValue;
+ }
}
+
+ _palette[r] = paletteValue;
}
-// if (num == 16) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue);
+ // if (num == 255) consolePrintf("pal:%d r:%d g:%d b:%d\n", r, red, green, blue);
+
+ colors += 4;
+ }
+}
+
+void OSystem_DS::setCursorPalette(const byte *colors, uint start, uint num) {
+
+// consolePrintf("Cursor palette set: start: %d, cols: %d\n", start, num);
+ for (unsigned int r = start; r < start + num; r++) {
+ int red = *colors;
+ int green = *(colors + 1);
+ int blue = *(colors + 2);
+
+ red >>= 3;
+ green >>= 3;
+ blue >>= 3;
+ u16 paletteValue = red | (green << 5) | (blue << 10);
+ _cursorPalette[r] = paletteValue;
+
colors += 4;
}
+
+ _disableCursorPalette = false;
}
bool OSystem_DS::grabRawScreen(Graphics::Surface* surf) {
@@ -184,9 +224,11 @@ void OSystem_DS::grabPalette(unsigned char *colors, uint start, uint num) {
}
+#define MISALIGNED16(ptr) (((u32) (ptr) & 1) != 0)
+
void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
-// consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h);
-
+ //consolePrintf("Copy rect %d, %d %d, %d ", x, y, w, h);
+ if (!_graphicsEnable) return;
if (w <= 1) return;
if (h < 0) return;
if (!DS::getIsDisplayMode8Bit()) return;
@@ -195,6 +237,9 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int
s32 stride;
u16* bgSub = (u16 *) BG_GFX_SUB;
+ // The DS video RAM doesn't support 8-bit writes because Nintendo wanted
+ // to save a few pennies/euro cents on the hardware.
+
if (_frameBufferExists) {
bg = (u16 *) _framebuffer.pixels;
stride = _framebuffer.pitch;
@@ -203,46 +248,117 @@ void OSystem_DS::copyRectToScreen(const byte *buf, int pitch, int x, int y, int
stride = DS::get8BitBackBufferStride();
}
- u16* src = (u16 *) buf;
-
- if (DS::getKeyboardEnable()) {
-
+ if (((pitch & 1) != 0) || ((w & 1) != 0) || (((int) (buf) & 1) != 0)) {
+
+ // Something is misaligned, so we have to use the slow but sure method
+
+ int by = 0;
+
for (int dy = y; dy < y + h; dy++) {
- u16* dest = bg + (dy * (stride >> 1)) + (x >> 1);
-
- DC_FlushRange(src, w << 1);
- DC_FlushRange(dest, w << 1);
- dmaCopyHalfWords(3, src, dest, w);
-
- src += pitch >> 1;
+ u8* dest = ((u8 *) (bg)) + (dy * stride) + x;
+ u8* destSub = ((u8 *) (bgSub)) + (dy * 512) + x;
+ u8* src = (u8 *) buf + (pitch * by);
+
+ u32 dx;
+
+ u32 pixelsLeft = w;
+
+ if (MISALIGNED16(dest)) {
+ // Read modify write
+
+ dest--;
+ u16 mix = *((u16 *) dest);
+
+ mix = (mix & 0x00FF) | (*src++ << 8);
+
+ *dest = mix;
+ *destSub = mix;
+
+ dest += 2;
+ destSub += 2;
+ pixelsLeft--;
+ }
+
+ // We can now assume dest is aligned
+ u16* dest16 = (u16 *) dest;
+ u16* destSub16 = (u16 *) destSub;
+
+ for (dx = 0; dx < pixelsLeft; dx+=2) {
+ u16 mix;
+
+ mix = *src + (*(src + 1) << 8);
+ *dest16++ = mix;
+ *destSub16++ = mix;
+ src += 2;
+ }
+
+ pixelsLeft -= dx;
+
+ // At the end we may have one pixel left over
+
+ if (pixelsLeft != 0) {
+ u16 mix = *dest16;
+
+ mix = (mix & 0x00FF) | ((*src++) << 8);
+
+ *dest16 = mix;
+ *destSub16 = mix;
+ }
+
+ by++;
+
}
-
+
+// consolePrintf("Slow method used!\n");
+
+
} else {
- for (int dy = y; dy < y + h; dy++) {
- u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1);
- u16* dest2 = bgSub + (dy << 8) + (x >> 1);
+
+ // Stuff is aligned to 16-bit boundaries, so it's safe to do DMA.
+
+ u16* src = (u16 *) buf;
+
+ if (DS::getKeyboardEnable()) {
+
+ for (int dy = y; dy < y + h; dy++) {
+ u16* dest = bg + (dy * (stride >> 1)) + (x >> 1);
- DC_FlushRange(src, w << 1);
- DC_FlushRange(dest1, w << 1);
- DC_FlushRange(dest2, w << 1);
-
- dmaCopyHalfWords(3, src, dest1, w);
- dmaCopyHalfWords(3, src, dest2, w);
-
- src += pitch >> 1;
- }
- }
+ DC_FlushRange(src, w << 1);
+ DC_FlushRange(dest, w << 1);
+ dmaCopyHalfWords(3, src, dest, w);
-// consolePrintf("Done\n");
+ while (dmaBusy(3));
+
+ src += pitch >> 1;
+ }
+
+ } else {
+ for (int dy = y; dy < y + h; dy++) {
+ u16* dest1 = bg + (dy * (stride >> 1)) + (x >> 1);
+ u16* dest2 = bgSub + (dy << 8) + (x >> 1);
+
+ DC_FlushRange(src, w << 1);
+ DC_FlushRange(dest1, w << 1);
+ DC_FlushRange(dest2, w << 1);
+
+ dmaCopyHalfWords(3, src, dest1, w);
-
+ if ((!_frameBufferExists) || (buf == _framebuffer.pixels)) {
+ dmaCopyHalfWords(2, src, dest2, w);
+ }
+ while (dmaBusy(2) || dmaBusy(3));
+
+ src += pitch >> 1;
+ }
+ }
+ }
+// consolePrintf("Done\n");
}
void OSystem_DS::updateScreen() {
- if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit()))
- {
+ if ((_frameBufferExists) && (DS::getIsDisplayMode8Bit())) {
_frameBufferExists = false;
// Copy temp framebuffer back to screen
@@ -253,6 +369,12 @@ void OSystem_DS::updateScreen() {
DS::doSoundCallback();
// DS::doTimerCallback();
DS::addEventsToQueue();
+
+ // Force back buffer usage for Nippon Safes, as it doesn't double buffer it's output
+ if (DS::getControlType() == DS::CONT_NIPPON) {
+ OSystem_DS::instance()->lockScreen();
+ OSystem_DS::instance()->unlockScreen();
+ }
}
void OSystem_DS::setShakePos(int shakeOffset) {
@@ -334,7 +456,21 @@ void OSystem_DS::warpMouse(int x, int y) {
}
void OSystem_DS::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int targetCursorScale) {
- DS::setCursorIcon(buf, w, h, keycolor, hotspotX, hotspotY);
+ if ((w > 0) && (w < 64) && (h > 0) && (h < 64))
+ {
+ memcpy(_cursorImage, buf, w * h);
+ _cursorW = w;
+ _cursorH = h;
+ _cursorHotX = hotspotX;
+ _cursorHotY = hotspotY;
+ _cursorKey = keycolor;
+ _cursorScale = targetCursorScale;
+ refreshCursor();
+ }
+}
+
+void OSystem_DS::refreshCursor() {
+ DS::setCursorIcon(_cursorImage, _cursorW, _cursorH, _cursorKey, _cursorHotX, _cursorHotY);
}
void OSystem_DS::addEvent(Common::Event& e) {
@@ -489,7 +625,11 @@ Common::SaveFileManager* OSystem_DS::getSavefileManager() {
if (DS::isGBAMPAvailable() && (!forceSram)) {
return &mpSaveManager;
} else {
+#ifdef GBA_SRAM_SAVE
return &saveManager;
+#else
+ return NULL;
+#endif
}
}
diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h
index 8c8d661ad8..16c8f41491 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.h
+++ b/backends/platform/ds/arm9/source/osystem_ds.h
@@ -52,17 +52,32 @@ protected:
Common::Event eventQueue[96];
int queuePos;
+#ifdef GBA_SRAM_SAVE
DSSaveFileManager saveManager;
+#endif
GBAMPSaveFileManager mpSaveManager;
DSAudioMixer* _mixer;
DSTimerManager* _timer;
Graphics::Surface _framebuffer;
bool _frameBufferExists;
-
+ bool _graphicsEnable;
static OSystem_DS* _instance;
+
+ u16 _palette[256];
+ u16 _cursorPalette[256];
+
+ u8 _cursorImage[64 * 64];
+ uint _cursorW;
+ uint _cursorH;
+ int _cursorHotX;
+ int _cursorHotY;
+ byte _cursorKey;
+ int _cursorScale;
+
Graphics::Surface* createTempFrameBuffer();
+ bool _disableCursorPalette;
public:
typedef void (*SoundProc)(byte *buf, int len);
@@ -159,7 +174,16 @@ public:
virtual void clearAutoComplete();
virtual void setCharactersEntered(int count);
+ u16 getDSPaletteEntry(u32 entry) { return _palette[entry]; }
+ u16 getDSCursorPaletteEntry(u32 entry) { return !_disableCursorPalette? _cursorPalette[entry]: _palette[entry]; }
+
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+
+ virtual void disableCursorPalette(bool dis) { _disableCursorPalette = dis; refreshCursor(); }
+
FilesystemFactory *getFilesystemFactory();
+
+ void refreshCursor();
};
static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
diff --git a/backends/platform/ds/arm9/source/portdefs.h b/backends/platform/ds/arm9/source/portdefs.h
index de7a5795f5..16f3d8cc9b 100644
--- a/backends/platform/ds/arm9/source/portdefs.h
+++ b/backends/platform/ds/arm9/source/portdefs.h
@@ -81,7 +81,10 @@ void consolePrintf(const char* s, ...);
#define ITCM_DATA __attribute__((section(".itcm")))
-
+// Since I can't change the engine at the moment (post lockdown) this define can go here.
+// This define changes the mouse-relative motion which doesn't make sense on a touch screen to
+// a more conventional form of input where the menus can be clicked on.
+#define LURE_CLICKABLE_MENUS
//#include "common/array.h"
//#include "common/str.h"
diff --git a/backends/platform/ds/arm9/source/ramsave.cpp b/backends/platform/ds/arm9/source/ramsave.cpp
index be355ce76f..a9f4e3d2fc 100644
--- a/backends/platform/ds/arm9/source/ramsave.cpp
+++ b/backends/platform/ds/arm9/source/ramsave.cpp
@@ -19,7 +19,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
- // Save in order 1,2,3,4,larger 2,5
+#ifdef GBA_SRAM_SAVE
+
+
#include "ramsave.h"
#include "nds.h"
#include "compressor/lz.h"
@@ -64,6 +66,7 @@ DSSaveFile::DSSaveFile(SCUMMSave* s, bool compressed, u8* data) {
}
isTempFile = false;
+ eosReached = false;
}
DSSaveFile::~DSSaveFile() {
@@ -167,11 +170,13 @@ int DSSaveFile::saveToSaveRAM(vu8* address) {
void DSSaveFile::reset() {
ptr = 0;
+ eosReached = false;
}
uint32 DSSaveFile::read(void *buf, uint32 size) {
if (ptr + size > save.size) {
size = save.size - ptr;
+ eosReached = true;
if (size < 0) size = 0;
}
memcpy(buf, saveData + ptr, size);
@@ -181,15 +186,15 @@ uint32 DSSaveFile::read(void *buf, uint32 size) {
return size;
}
-uint32 DSSaveFile::pos() const {
+int32 DSSaveFile::pos() const {
return ptr;
}
-uint32 DSSaveFile::size() const {
+int32 DSSaveFile::size() const {
return save.size;
}
-void DSSaveFile::seek(int32 pos, int whence) {
+bool DSSaveFile::seek(int32 pos, int whence) {
switch (whence) {
case SEEK_SET: {
ptr = pos;
@@ -204,15 +209,22 @@ void DSSaveFile::seek(int32 pos, int whence) {
break;
}
}
+ eosReached = false;
+ return true;
}
bool DSSaveFile::eos() const {
- return ptr >= (int) save.size;
+ return eosReached;
}
-void DSSaveFile::skip(uint32 bytes) {
+void DSSaveFile::clearErr() {
+ eosReached = false;
+}
+
+bool DSSaveFile::skip(uint32 bytes) {
ptr = ptr + bytes;
if (ptr > (int) save.size) ptr = save.size;
+ return true;
}
uint32 DSSaveFile::write(const void *buf, uint32 size) {
@@ -227,7 +239,7 @@ uint32 DSSaveFile::write(const void *buf, uint32 size) {
return size;
}
-bool DSSaveFile::matches(char* prefix, int num) {
+bool DSSaveFile::matches(const char *prefix, int num) {
char str[16];
if (isValid()) {
sprintf(str, "%s%02d", prefix, num);
@@ -241,7 +253,7 @@ bool DSSaveFile::matches(char* prefix, int num) {
}
}
-bool DSSaveFile::matches(char* filename) {
+bool DSSaveFile::matches(const char *filename) {
if (isValid()) {
return !strcmp(save.name, filename);
} else {
@@ -522,3 +534,5 @@ int DSSaveFileManager::getExtraData() {
return 0;
}
}
+
+#endif
diff --git a/backends/platform/ds/arm9/source/ramsave.h b/backends/platform/ds/arm9/source/ramsave.h
index f919da18db..034e957b7f 100644
--- a/backends/platform/ds/arm9/source/ramsave.h
+++ b/backends/platform/ds/arm9/source/ramsave.h
@@ -52,6 +52,7 @@ class DSSaveFile : public Common::InSaveFile, public Common::OutSaveFile {
SCUMMSave* origHeader;
bool isOpenFlag;
bool isTempFile;
+ bool eosReached;
public:
DSSaveFile();
@@ -62,11 +63,12 @@ public:
bool isOpen() const { return isOpenFlag; }
virtual bool eos() const;
- virtual void skip(uint32 size);
+ virtual void clearErr();
+ virtual bool skip(uint32 size);
- virtual uint32 pos() const;
- virtual uint32 size() const;
- virtual void seek(int32 pos, int whence);
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ virtual bool seek(int32 pos, int whence);
uint32 read(void *buf, uint32 size);
uint32 write(const void *buf, uint32 size);
@@ -76,8 +78,8 @@ public:
bool isValid() { return save.isValid; }
bool isTemp() { return isTempFile; }
- bool matches(char* prefix, int num);
- bool matches(char* filename);
+ bool matches(const char *prefix, int num);
+ bool matches(const char *filename);
void clearData();
void compress();
diff --git a/backends/platform/ds/arm9/source/touchkeyboard.cpp b/backends/platform/ds/arm9/source/touchkeyboard.cpp
index 11832f4e3a..85f80fac92 100644
--- a/backends/platform/ds/arm9/source/touchkeyboard.cpp
+++ b/backends/platform/ds/arm9/source/touchkeyboard.cpp
@@ -402,6 +402,23 @@ void createKeyEvent(int keyNum, Common::Event& event)
}
}
+void releaseAllKeys() {
+ for (int r = 0; r < DS_NUM_KEYS; r++) {
+ if (keys[r].pressed) {
+ DS::setKeyHighlight(r, false);
+
+ OSystem_DS* system = OSystem_DS::instance();
+
+ Common::Event event;
+ createKeyEvent(r, event);
+ event.type = Common::EVENT_KEYUP;
+ system->addEvent(event);
+
+ keys[r].pressed = false;
+ }
+ }
+}
+
void addKeyboardEvents() {
bool resetShift = false;
@@ -446,7 +463,7 @@ void addKeyboardEvents() {
// consolePrintf("Key: %d\n", r);
if ((keys[r].character == Common::KEYCODE_INVALID)) {
// Close button
- DS::closed = true;
+ //DS::closed = true;
} else {
createKeyEvent(r, event);
}
@@ -492,9 +509,14 @@ void addKeyboardEvents() {
OSystem_DS* system = OSystem_DS::instance();
Common::Event event;
- createKeyEvent(r, event);
- event.type = Common::EVENT_KEYUP;
- system->addEvent(event);
+ if ((keys[r].character == Common::KEYCODE_INVALID)) {
+ // Close button
+ DS::closed = true;
+ } else {
+ createKeyEvent(r, event);
+ event.type = Common::EVENT_KEYUP;
+ system->addEvent(event);
+ }
keys[r].pressed = false;
diff --git a/backends/platform/ds/arm9/source/touchkeyboard.h b/backends/platform/ds/arm9/source/touchkeyboard.h
index 8a5fc728ce..91efbc1e9a 100644
--- a/backends/platform/ds/arm9/source/touchkeyboard.h
+++ b/backends/platform/ds/arm9/source/touchkeyboard.h
@@ -40,6 +40,7 @@ bool getKeyboardClosed();
void addAutoComplete(char* word);
void clearAutoComplete();
void setCharactersEntered(int count);
+void releaseAllKeys();
}
diff --git a/backends/platform/ds/logog.bmp b/backends/platform/ds/logog.bmp
new file mode 100644
index 0000000000..9c194d3f82
--- /dev/null
+++ b/backends/platform/ds/logog.bmp
Binary files differ
diff --git a/backends/platform/ds/makefile b/backends/platform/ds/makefile
index 3fb19e939c..a9fbb13637 100644
--- a/backends/platform/ds/makefile
+++ b/backends/platform/ds/makefile
@@ -36,3 +36,23 @@ allbuilds:
make all SCUMM_BUILD=f
make semiclean
make all SCUMM_BUILD=g
+ make semiclean
+ make all SCUMM_BUILD=h
+
+allbuildssafe:
+ make clean SCUMM_BUILD=a
+ make all SCUMM_BUILD=a
+ make clean SCUMM_BUILD=b
+ make all SCUMM_BUILD=b
+ make clean SCUMM_BUILD=c
+ make all SCUMM_BUILD=c
+ make clean SCUMM_BUILD=d
+ make all SCUMM_BUILD=d
+ make clean SCUMM_BUILD=e
+ make all SCUMM_BUILD=e
+ make clean SCUMM_BUILD=f
+ make all SCUMM_BUILD=f
+ make clean SCUMM_BUILD=g
+ make all SCUMM_BUILD=g
+ make clean SCUMM_BUILD=h
+ make all SCUMM_BUILD=h
diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp
index c138f6c54d..e5f062ed35 100644
--- a/backends/platform/gp2x/gp2x.cpp
+++ b/backends/platform/gp2x/gp2x.cpp
@@ -219,7 +219,7 @@ void OSystem_GP2X::initBackend() {
// Create the savefile manager, if none exists yet (we check for this to
// allow subclasses to provide their own).
if (_savefile == 0) {
- _savefile = new DefaultSaveFileManager();
+ _savefile = new DefaultSaveFileManager(savePath);
}
// Create and hook up the mixer, if none exists yet (we check for this to
diff --git a/backends/platform/iphone/iphone_keyboard.m b/backends/platform/iphone/iphone_keyboard.m
index bd4948e30a..fda481933d 100644
--- a/backends/platform/iphone/iphone_keyboard.m
+++ b/backends/platform/iphone/iphone_keyboard.m
@@ -54,8 +54,7 @@
@implementation SoftKeyboard
- (id)initWithFrame:(CGRect)frame {
- //self = [super initWithFrame:frame];
- self = [super initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f)];
+ self = [super initWithFrame:frame];
inputDelegate = nil;
inputView = [[TextInputHandler alloc] initWithKeyboard:self];
return self;
diff --git a/backends/platform/iphone/iphone_main.m b/backends/platform/iphone/iphone_main.m
index b01e9f3f34..6b709b0803 100644
--- a/backends/platform/iphone/iphone_main.m
+++ b/backends/platform/iphone/iphone_main.m
@@ -79,10 +79,7 @@ int main(int argc, char** argv) {
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// hide the status bar
[UIHardware _setStatusBarHeight:0.0f];
- //[self setStatusBarMode:2 orientation:0 duration:0.0f fenceID:0];
-
- //[self setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO];
- [self setStatusBarHidden:YES animated:YES];
+ [self setStatusBarHidden:YES animated:NO];
_window = [[UIWindow alloc] initWithContentRect: [UIHardware fullScreenApplicationContentRect]];
[_window retain];
@@ -103,9 +100,13 @@ int main(int argc, char** argv) {
- (void)applicationResume:(GSEventRef)event {
[self removeApplicationBadge];
- [UIHardware _setStatusBarHeight:0.0f];
- [self setStatusBarHidden:YES animated:YES];
[_view applicationResume];
+
+ // Workaround, need to "hide" and unhide the statusbar to properly remove it,
+ // since the Springboard has put it back without apparently flagging our application.
+ [self setStatusBarHidden:NO animated:NO]; // hide status bar
+ [UIHardware _setStatusBarHeight:0.0f];
+ [self setStatusBarHidden:YES animated:NO]; // hide status bar
}
- (void)deviceOrientationChanged:(GSEvent *)event {
diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m
index 89f159c1d9..910f14ab58 100644
--- a/backends/platform/iphone/iphone_video.m
+++ b/backends/platform/iphone/iphone_video.m
@@ -169,10 +169,6 @@ bool getLocalMouseCoords(CGPoint *point) {
nil
];
- if (_screenSurface != nil) {
- //[[sharedInstance _layer] removeSublayer: screenLayer];
- }
-
//("Allocating surface: %d\n", allocSize);
_screenSurface = CoreSurfaceBufferCreate((CFDictionaryRef)dict);
//printf("Surface created.\n");
@@ -205,10 +201,13 @@ bool getLocalMouseCoords(CGPoint *point) {
[screenLayer setFrame: _screenRect];
} else {
float ratio = (float)_height / (float)_width;
- _screenRect = CGRectMake(0, 0, _fullWidth, _fullWidth * ratio);
+ int height = _fullWidth * ratio;
+ //printf("Making rect (%u, %u)\n", _fullWidth, height);
+ _screenRect = CGRectMake(0, 0, _fullWidth - 1, height - 1);
[screenLayer setFrame: _screenRect];
- CGRect keyFrame = CGRectMake(0.0f, _screenRect.size.height, _fullWidth, _fullHeight - _screenRect.size.height);
+ //CGRect keyFrame = CGRectMake(0.0f, _screenRect.size.height, _fullWidth, _fullHeight - _screenRect.size.height);
+ CGRect keyFrame = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
if (_keyboardView == nil) {
_keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame];
[_keyboardView setInputDelegate:self];
@@ -250,9 +249,6 @@ bool getLocalMouseCoords(CGPoint *point) {
[self lock];
id event = [_events objectAtIndex: 0];
- if (event == nil) {
- return nil;
- }
[_events removeObjectAtIndex: 0];
[self unlock];
diff --git a/backends/platform/iphone/osys_iphone.cpp b/backends/platform/iphone/osys_iphone.cpp
index fdef911d0a..521e91a87e 100644
--- a/backends/platform/iphone/osys_iphone.cpp
+++ b/backends/platform/iphone/osys_iphone.cpp
@@ -56,24 +56,27 @@ const OSystem::GraphicsMode OSystem_IPHONE::s_supportedGraphicsModes[] = {
AQCallbackStruct OSystem_IPHONE::s_AudioQueue;
SoundProc OSystem_IPHONE::s_soundCallback = NULL;
void *OSystem_IPHONE::s_soundParam = NULL;
-bool OSystem_IPHONE::s_is113OrHigher = false;
OSystem_IPHONE::OSystem_IPHONE() :
_savefile(NULL), _mixer(NULL), _timer(NULL), _offscreen(NULL),
_overlayVisible(false), _overlayBuffer(NULL), _fullscreen(NULL),
_mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0),
_secondaryTapped(false), _lastSecondaryTap(0), _screenOrientation(kScreenOrientationFlippedLandscape),
- _needEventRestPeriod(false), _mouseClickAndDragEnabled(false),
+ _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), _touchpadModeEnabled(false),
_gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false),
- _mouseDirty(false), _timeSuspended(0)
+ _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1)
+
{
_queuedInputEvent.type = (Common::EventType)0;
_lastDrawnMouseRect = Common::Rect(0, 0, 0, 0);
+
+ _fsFactory = new POSIXFilesystemFactory();
}
OSystem_IPHONE::~OSystem_IPHONE() {
AudioQueueDispose(s_AudioQueue.queue, true);
+ delete _fsFactory;
delete _savefile;
delete _mixer;
delete _timer;
@@ -88,7 +91,7 @@ int OSystem_IPHONE::timerHandler(int t) {
}
void OSystem_IPHONE::initBackend() {
- _savefile = new DefaultSaveFileManager();
+ _savefile = new DefaultSaveFileManager(SCUMMVM_SAVE_PATH);
_timer = new DefaultTimerManager();
gettimeofday(&_startTime, NULL);
@@ -665,8 +668,8 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) {
float xUnit, yUnit;
if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit)) {
- int x;
- int y;
+ int x = 0;
+ int y = 0;
switch (_screenOrientation) {
case kScreenOrientationPortrait:
x = (int)(xUnit * _screenWidth);
@@ -684,334 +687,436 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) {
switch ((InputEvent)eventType) {
case kInputMouseDown:
- //printf("Mouse down at (%u, %u)\n", x, y);
-
- // Workaround: kInputMouseSecondToggled isn't always sent when the
- // secondary finger is lifted. Need to make sure we get out of that mode.
- _secondaryTapped = false;
-
- warpMouse(x, y);
- // event.type = Common::EVENT_MOUSEMOVE;
- // event.mouse.x = _mouseX;
- // event.mouse.y = _mouseY;
-
- if (_mouseClickAndDragEnabled) {
- event.type = Common::EVENT_LBUTTONDOWN;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
- return true;
- } else {
- _lastMouseDown = curTime;
- }
- return false;
+ if (!handleEvent_mouseDown(event, x, y))
+ return false;
break;
- case kInputMouseUp:
- //printf("Mouse up at (%u, %u)\n", x, y);
- if (_mouseClickAndDragEnabled) {
- event.type = Common::EVENT_LBUTTONUP;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
- } else {
- if (curTime - _lastMouseDown < 250) {
- event.type = Common::EVENT_LBUTTONDOWN;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
-
- _queuedInputEvent.type = Common::EVENT_LBUTTONUP;
- _queuedInputEvent.mouse.x = _mouseX;
- _queuedInputEvent.mouse.y = _mouseY;
- _lastMouseTap = curTime;
- _needEventRestPeriod = true;
- } else
- return false;
- }
+ case kInputMouseUp:
+ if (!handleEvent_mouseUp(event, x, y))
+ return false;
break;
+
case kInputMouseDragged:
- //printf("Mouse dragged at (%u, %u)\n", x, y);
- if (_secondaryTapped) {
- if (_gestureStartX == -1 || _gestureStartY == -1) {
- return false;
- }
-
- int vecX = (x - _gestureStartX);
- int vecY = (y - _gestureStartY);
- int lengthSq = vecX * vecX + vecY * vecY;
- //printf("Lengthsq: %u\n", lengthSq);
-
- if (lengthSq > 15000) { // Long enough gesture to react upon.
- _gestureStartX = -1;
- _gestureStartY = -1;
-
- float vecLength = sqrt(lengthSq);
- float vecXNorm = vecX / vecLength;
- float vecYNorm = vecY / vecLength;
-
- //printf("Swipe vector: (%.2f, %.2f)\n", vecXNorm, vecYNorm);
-
- if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm > 0.75) {
- // Swipe down
- event.type = Common::EVENT_KEYDOWN;
- _queuedInputEvent.type = Common::EVENT_KEYUP;
-
- event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
- event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_F5;
- event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_F5;
- _needEventRestPeriod = true;
- } else if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm < -0.75) {
- // Swipe up
- _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
- const char *dialogMsg;
- if (_mouseClickAndDragEnabled)
- dialogMsg = "Mouse-click-and-drag mode enabled.";
- else
- dialogMsg = "Mouse-click-and-drag mode disabled.";
- GUI::TimedMessageDialog dialog(dialogMsg, 1500);
- dialog.runModal();
- return false;
- } else if (vecXNorm > 0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) {
- // Swipe right
- // _secondaryTapped = !_secondaryTapped;
- // _gestureStartX = x;
- // _gestureStartY = y;
- //
- // GUI::TimedMessageDialog dialog("Forcing toggle of pressed state.", 1500);
- // dialog.runModal();
- return false;
- } else if (vecXNorm < -0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) {
- // Swipe left
- return false;
- } else
- return false;
- } else
- return false;
- } else {
- event.type = Common::EVENT_MOUSEMOVE;
- event.mouse.x = x;
- event.mouse.y = y;
- warpMouse(x, y);
- }
+ if (!handleEvent_mouseDragged(event, x, y))
+ return false;
break;
+
case kInputMouseSecondToggled:
_secondaryTapped = !_secondaryTapped;
//printf("Mouse second at (%u, %u). State now %s.\n", x, y, _secondaryTapped ? "on" : "off");
if (_secondaryTapped) {
- _lastSecondaryDown = curTime;
- _gestureStartX = x;
- _gestureStartY = y;
- if (_mouseClickAndDragEnabled) {
- event.type = Common::EVENT_LBUTTONUP;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
-
- _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN;
- _queuedInputEvent.mouse.x = _mouseX;
- _queuedInputEvent.mouse.y = _mouseY;
- }
- else
+ if (!handleEvent_secondMouseDown(event, x, y))
return false;
} else {
- if (curTime - _lastSecondaryDown < 250 ) {
- if (curTime - _lastSecondaryTap < 250 && !_overlayVisible) {
- event.type = Common::EVENT_KEYDOWN;
- _queuedInputEvent.type = Common::EVENT_KEYUP;
-
- event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
- event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
- event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
- _needEventRestPeriod = true;
- _lastSecondaryTap = 0;
- } else if (!_mouseClickAndDragEnabled) {
- event.type = Common::EVENT_RBUTTONDOWN;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
- _queuedInputEvent.type = Common::EVENT_RBUTTONUP;
- _queuedInputEvent.mouse.x = _mouseX;
- _queuedInputEvent.mouse.y = _mouseY;
- _lastSecondaryTap = curTime;
- _needEventRestPeriod = true;
- }
- }
- if (_mouseClickAndDragEnabled) {
- event.type = Common::EVENT_RBUTTONUP;
- event.mouse.x = _mouseX;
- event.mouse.y = _mouseY;
- }
- }
- break;
- case kInputOrientationChanged:
- //printf("Orientation: %i", (int)xUnit);
-
- ScreenOrientation newOrientation;
- switch ((int)xUnit) {
- case 1:
- newOrientation = kScreenOrientationPortrait;
- break;
- case 3:
- newOrientation = kScreenOrientationLandscape;
- break;
- case 4:
- newOrientation = kScreenOrientationFlippedLandscape;
- break;
- default:
+ if (!handleEvent_secondMouseUp(event, x, y))
return false;
}
+ break;
-
- if (_screenOrientation != newOrientation) {
- _screenOrientation = newOrientation;
- if (_screenOrientation != kScreenOrientationPortrait)
- iPhone_initSurface(_screenHeight, _screenWidth, true);
- else
- iPhone_initSurface(_screenWidth, _screenHeight, false);
-
- dirtyFullScreen();
- updateScreen();
- }
+ case kInputOrientationChanged:
+ handleEvent_orientationChanged((int)xUnit);
+ return false;
break;
case kInputApplicationSuspended:
suspendLoop();
+ return false;
break;
- case kInputKeyPressed: {
- int keyPressed = (int)xUnit;
- int ascii = keyPressed;
- //printf("key: %i\n", keyPressed);
-
- // We remap some of the iPhone keyboard keys.
- // The first ten here are the row of symbols below the numeric keys.
- switch (keyPressed) {
- case 45:
- keyPressed = Common::KEYCODE_F1;
- ascii = Common::ASCII_F1;
- break;
- case 47:
- keyPressed = Common::KEYCODE_F2;
- ascii = Common::ASCII_F2;
- break;
- case 58:
- keyPressed = Common::KEYCODE_F3;
- ascii = Common::ASCII_F3;
- break;
- case 59:
- keyPressed = Common::KEYCODE_F4;
- ascii = Common::ASCII_F4;
- break;
- case 40:
- keyPressed = Common::KEYCODE_F5;
- ascii = Common::ASCII_F5;
- break;
- case 41:
- keyPressed = Common::KEYCODE_F6;
- ascii = Common::ASCII_F6;
- break;
- case 36:
- keyPressed = Common::KEYCODE_F7;
- ascii = Common::ASCII_F7;
- break;
- case 38:
- keyPressed = Common::KEYCODE_F8;
- ascii = Common::ASCII_F8;
- break;
- case 64:
- keyPressed = Common::KEYCODE_F9;
- ascii = Common::ASCII_F9;
- break;
- case 34:
- keyPressed = Common::KEYCODE_F10;
- ascii = Common::ASCII_F10;
- break;
- case 10:
- keyPressed = Common::KEYCODE_RETURN;
- ascii = Common::ASCII_RETURN;
- break;
- }
- event.type = Common::EVENT_KEYDOWN;
- _queuedInputEvent.type = Common::EVENT_KEYUP;
+ case kInputKeyPressed:
+ handleEvent_keyPressed(event, (int)xUnit);
+ break;
- event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
- event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed;
- event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii;
- _needEventRestPeriod = true;
+ case kInputSwipe:
+ if (!handleEvent_swipe(event, (int)xUnit))
+ return false;
break;
- }
- case kInputSwipe: {
- Common::KeyCode keycode = Common::KEYCODE_INVALID;
- switch (_screenOrientation) {
- case kScreenOrientationPortrait:
- switch ((UIViewSwipeDirection)xUnit) {
- case kUIViewSwipeUp:
- keycode = Common::KEYCODE_UP;
- break;
- case kUIViewSwipeDown:
- keycode = Common::KEYCODE_DOWN;
- break;
- case kUIViewSwipeLeft:
- keycode = Common::KEYCODE_LEFT;
- break;
- case kUIViewSwipeRight:
- keycode = Common::KEYCODE_RIGHT;
- break;
- default:
- return false;
- }
- break;
- case kScreenOrientationLandscape:
- switch ((UIViewSwipeDirection)xUnit) {
- case kUIViewSwipeUp:
- keycode = Common::KEYCODE_LEFT;
- break;
- case kUIViewSwipeDown:
- keycode = Common::KEYCODE_RIGHT;
- break;
- case kUIViewSwipeLeft:
- keycode = Common::KEYCODE_DOWN;
- break;
- case kUIViewSwipeRight:
- keycode = Common::KEYCODE_UP;
- break;
- default:
- return false;
- }
- break;
- case kScreenOrientationFlippedLandscape:
- switch ((UIViewSwipeDirection)xUnit) {
- case kUIViewSwipeUp:
- keycode = Common::KEYCODE_RIGHT;
- break;
- case kUIViewSwipeDown:
- keycode = Common::KEYCODE_LEFT;
- break;
- case kUIViewSwipeLeft:
- keycode = Common::KEYCODE_UP;
- break;
- case kUIViewSwipeRight:
- keycode = Common::KEYCODE_DOWN;
- break;
- default:
- return false;
- }
- break;
- }
+ default:
+ break;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool OSystem_IPHONE::handleEvent_mouseDown(Common::Event &event, int x, int y) {
+ printf("Mouse down at (%u, %u)\n", x, y);
+
+ // Workaround: kInputMouseSecondToggled isn't always sent when the
+ // secondary finger is lifted. Need to make sure we get out of that mode.
+ _secondaryTapped = false;
+
+ if (_touchpadModeEnabled) {
+ _lastPadX = x;
+ _lastPadY = y;
+ } else
+ warpMouse(x, y);
+
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ return true;
+ } else {
+ _lastMouseDown = getMillis();
+ }
+ return false;
+}
+
+bool OSystem_IPHONE::handleEvent_mouseUp(Common::Event &event, int x, int y) {
+ //printf("Mouse up at (%u, %u)\n", x, y);
+
+ if (_secondaryTapped) {
+ _secondaryTapped = false;
+ if (!handleEvent_secondMouseUp(event, x, y))
+ return false;
+ }
+ else if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ } else {
+ if (getMillis() - _lastMouseDown < 250) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+
+ _queuedInputEvent.type = Common::EVENT_LBUTTONUP;
+ _queuedInputEvent.mouse.x = _mouseX;
+ _queuedInputEvent.mouse.y = _mouseY;
+ _lastMouseTap = getMillis();
+ _needEventRestPeriod = true;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool OSystem_IPHONE::handleEvent_secondMouseDown(Common::Event &event, int x, int y) {
+ _lastSecondaryDown = getMillis();
+ _gestureStartX = x;
+ _gestureStartY = y;
+
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+
+ _queuedInputEvent.type = Common::EVENT_RBUTTONDOWN;
+ _queuedInputEvent.mouse.x = _mouseX;
+ _queuedInputEvent.mouse.y = _mouseY;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+bool OSystem_IPHONE::handleEvent_secondMouseUp(Common::Event &event, int x, int y) {
+ int curTime = getMillis();
+
+ if (curTime - _lastSecondaryDown < 400 ) {
+ //printf("Right tap!\n");
+ if (curTime - _lastSecondaryTap < 400 && !_overlayVisible) {
+ //printf("Right escape!\n");
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE;
+ _needEventRestPeriod = true;
+ _lastSecondaryTap = 0;
+ } else if (!_mouseClickAndDragEnabled) {
+ //printf("Rightclick!\n");
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ _queuedInputEvent.type = Common::EVENT_RBUTTONUP;
+ _queuedInputEvent.mouse.x = _mouseX;
+ _queuedInputEvent.mouse.y = _mouseY;
+ _lastSecondaryTap = curTime;
+ _needEventRestPeriod = true;
+ } else {
+ //printf("Right nothing!\n");
+ return false;
+ }
+ }
+ if (_mouseClickAndDragEnabled) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ }
+
+ return true;
+}
+
+bool OSystem_IPHONE::handleEvent_mouseDragged(Common::Event &event, int x, int y) {
+ if (_lastDragPosX == x && _lastDragPosY == y)
+ return false;
+
+ _lastDragPosX = x;
+ _lastDragPosY = y;
+
+ //printf("Mouse dragged at (%u, %u)\n", x, y);
+ if (_secondaryTapped) {
+ if (_gestureStartX == -1 || _gestureStartY == -1) {
+ return false;
+ }
+
+ int vecX = (x - _gestureStartX);
+ int vecY = (y - _gestureStartY);
+ int lengthSq = vecX * vecX + vecY * vecY;
+ //printf("Lengthsq: %u\n", lengthSq);
- event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode;
- event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0;
+ if (lengthSq > 15000) { // Long enough gesture to react upon.
+ _gestureStartX = -1;
+ _gestureStartY = -1;
+
+ float vecLength = sqrt(lengthSq);
+ float vecXNorm = vecX / vecLength;
+ float vecYNorm = vecY / vecLength;
+
+ //printf("Swipe vector: (%.2f, %.2f)\n", vecXNorm, vecYNorm);
+
+ if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm > 0.75) {
+ // Swipe down
event.type = Common::EVENT_KEYDOWN;
_queuedInputEvent.type = Common::EVENT_KEYUP;
+
event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_F5;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_F5;
_needEventRestPeriod = true;
- break;
- }
+ } else if (vecXNorm > -0.50 && vecXNorm < 0.50 && vecYNorm < -0.75) {
+ // Swipe up
+ _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled;
+ const char *dialogMsg;
+ if (_mouseClickAndDragEnabled)
+ dialogMsg = "Mouse-click-and-drag mode enabled.";
+ else
+ dialogMsg = "Mouse-click-and-drag mode disabled.";
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
- default:
- break;
+ } else if (vecXNorm > 0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) {
+ // Swipe right
+ _touchpadModeEnabled = !_touchpadModeEnabled;
+ const char *dialogMsg;
+ if (_touchpadModeEnabled)
+ dialogMsg = "Touchpad mode enabled.";
+ else
+ dialogMsg = "Touchpad mode disabled.";
+ GUI::TimedMessageDialog dialog(dialogMsg, 1500);
+ dialog.runModal();
+ return false;
+
+ } else if (vecXNorm < -0.75 && vecYNorm > -0.5 && vecYNorm < 0.5) {
+ // Swipe left
+ return false;
+ } else
+ return false;
+ } else
+ return false;
+ } else {
+ int mouseNewPosX;
+ int mouseNewPosY;
+ if (_touchpadModeEnabled ) {
+ int deltaX = _lastPadX - x;
+ int deltaY = _lastPadY - y;
+ _lastPadX = x;
+ _lastPadY = y;
+
+ mouseNewPosX = (int)(_mouseX - deltaX / 0.5f);
+ mouseNewPosY = (int)(_mouseY - deltaY / 0.5f);
+
+ if (mouseNewPosX < 0)
+ mouseNewPosX = 0;
+ else if (mouseNewPosX > _screenWidth)
+ mouseNewPosX = _screenWidth;
+
+ if (mouseNewPosY < 0)
+ mouseNewPosY = 0;
+ else if (mouseNewPosY > _screenHeight)
+ mouseNewPosY = _screenHeight;
+
+ } else {
+ mouseNewPosX = x;
+ mouseNewPosY = y;
}
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse.x = mouseNewPosX;
+ event.mouse.y = mouseNewPosY;
+ warpMouse(mouseNewPosX, mouseNewPosY);
+ }
+
+ return true;
+}
- return true;
+void OSystem_IPHONE::handleEvent_orientationChanged(int orientation) {
+ //printf("Orientation: %i\n", orientation);
+
+ ScreenOrientation newOrientation;
+ switch (orientation) {
+ case 1:
+ newOrientation = kScreenOrientationPortrait;
+ break;
+ case 3:
+ newOrientation = kScreenOrientationLandscape;
+ break;
+ case 4:
+ newOrientation = kScreenOrientationFlippedLandscape;
+ break;
+ default:
+ return;
}
- return false;
+
+
+ if (_screenOrientation != newOrientation) {
+ _screenOrientation = newOrientation;
+ if (_screenOrientation != kScreenOrientationPortrait)
+ iPhone_initSurface(_screenHeight, _screenWidth, true);
+ else
+ iPhone_initSurface(_screenWidth, _screenHeight, false);
+
+ dirtyFullScreen();
+ updateScreen();
+ }
+}
+
+void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPressed) {
+ int ascii = keyPressed;
+ //printf("key: %i\n", keyPressed);
+
+ // We remap some of the iPhone keyboard keys.
+ // The first ten here are the row of symbols below the numeric keys.
+ switch (keyPressed) {
+ case 45:
+ keyPressed = Common::KEYCODE_F1;
+ ascii = Common::ASCII_F1;
+ break;
+ case 47:
+ keyPressed = Common::KEYCODE_F2;
+ ascii = Common::ASCII_F2;
+ break;
+ case 58:
+ keyPressed = Common::KEYCODE_F3;
+ ascii = Common::ASCII_F3;
+ break;
+ case 59:
+ keyPressed = Common::KEYCODE_F4;
+ ascii = Common::ASCII_F4;
+ break;
+ case 40:
+ keyPressed = Common::KEYCODE_F5;
+ ascii = Common::ASCII_F5;
+ break;
+ case 41:
+ keyPressed = Common::KEYCODE_F6;
+ ascii = Common::ASCII_F6;
+ break;
+ case 36:
+ keyPressed = Common::KEYCODE_F7;
+ ascii = Common::ASCII_F7;
+ break;
+ case 38:
+ keyPressed = Common::KEYCODE_F8;
+ ascii = Common::ASCII_F8;
+ break;
+ case 64:
+ keyPressed = Common::KEYCODE_F9;
+ ascii = Common::ASCII_F9;
+ break;
+ case 34:
+ keyPressed = Common::KEYCODE_F10;
+ ascii = Common::ASCII_F10;
+ break;
+ case 10:
+ keyPressed = Common::KEYCODE_RETURN;
+ ascii = Common::ASCII_RETURN;
+ break;
+ }
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = (Common::KeyCode)keyPressed;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = ascii;
+ _needEventRestPeriod = true;
+}
+
+bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction) {
+ Common::KeyCode keycode = Common::KEYCODE_INVALID;
+ switch (_screenOrientation) {
+ case kScreenOrientationPortrait:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_UP;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case kScreenOrientationLandscape:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_UP;
+ break;
+ default:
+ return false;
+ }
+ break;
+ case kScreenOrientationFlippedLandscape:
+ switch ((UIViewSwipeDirection)direction) {
+ case kUIViewSwipeUp:
+ keycode = Common::KEYCODE_RIGHT;
+ break;
+ case kUIViewSwipeDown:
+ keycode = Common::KEYCODE_LEFT;
+ break;
+ case kUIViewSwipeLeft:
+ keycode = Common::KEYCODE_UP;
+ break;
+ case kUIViewSwipeRight:
+ keycode = Common::KEYCODE_DOWN;
+ break;
+ default:
+ return false;
+ }
+ break;
+ }
+
+ event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode;
+ event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0;
+ event.type = Common::EVENT_KEYDOWN;
+ _queuedInputEvent.type = Common::EVENT_KEYUP;
+ event.kbd.flags = _queuedInputEvent.kbd.flags = 0;
+ _needEventRestPeriod = true;
+
+ return true;
}
void OSystem_IPHONE::suspendLoop() {
@@ -1020,16 +1125,17 @@ void OSystem_IPHONE::suspendLoop() {
float xUnit, yUnit;
uint32 startTime = getMillis();
- AudioQueueStop(s_AudioQueue.queue, true);
-
+ stopSoundsystem();
+
while (!done) {
if (iPhone_fetchEvent(&eventType, &xUnit, &yUnit))
if ((InputEvent)eventType == kInputApplicationResumed)
done = true;
usleep(100000);
}
+
+ startSoundsystem();
- AudioQueueStart(s_AudioQueue.queue, NULL);
_timeSuspended += getMillis() - startTime;
}
@@ -1107,7 +1213,10 @@ void OSystem_IPHONE::setupMixer() {
s_soundCallback = mixCallback;
s_soundParam = this;
+ startSoundsystem();
+}
+void OSystem_IPHONE::startSoundsystem() {
s_AudioQueue.dataFormat.mSampleRate = AUDIO_SAMPLE_RATE;
s_AudioQueue.dataFormat.mFormatID = kAudioFormatLinearPCM;
s_AudioQueue.dataFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
@@ -1147,6 +1256,17 @@ void OSystem_IPHONE::setupMixer() {
_mixer->setReady(true);
}
+void OSystem_IPHONE::stopSoundsystem() {
+ AudioQueueStop(s_AudioQueue.queue, true);
+
+ for (int i = 0; i < AUDIO_BUFFERS; i++) {
+ AudioQueueFreeBuffer(s_AudioQueue.queue, s_AudioQueue.buffers[i]);
+ }
+
+ AudioQueueDispose(s_AudioQueue.queue, true);
+ _mixer->setReady(false);
+}
+
int OSystem_IPHONE::getOutputSampleRate() const {
return AUDIO_SAMPLE_RATE;
}
@@ -1196,33 +1316,6 @@ const char* OSystem_IPHONE::getConfigPath() {
return SCUMMVM_PREFS_PATH;
}
-const char* OSystem_IPHONE::getSavePath() {
- return SCUMMVM_SAVE_PATH;
-}
-
-void OSystem_IPHONE::migrateApp() {
- // Migrate to the new 1.1.3 directory structure, if needed.
-
- FilesystemNode file("/var/mobile");
- if (file.exists() && file.isDirectory()) {
- // We have 1.1.3 or above.
- s_is113OrHigher = true;
- file = FilesystemNode(SCUMMVM_ROOT_PATH);
- if (!file.exists()) {
- system("mkdir " SCUMMVM_ROOT_PATH);
- system("mkdir " SCUMMVM_SAVE_PATH);
-
- // Copy over the prefs file
- system("cp " SCUMMVM_OLD_PREFS_PATH " " SCUMMVM_PREFS_PATH);
-
- file = FilesystemNode(SCUMMVM_OLD_SAVE_PATH);
- // Copy over old savegames to the new directory.
- if (file.exists() && file.isDirectory())
- system("cp " SCUMMVM_OLD_SAVE_PATH "/* " SCUMMVM_SAVE_PATH "/");
- }
- }
-}
-
void iphone_main(int argc, char *argv[]) {
//OSystem_IPHONE::migrateApp();
@@ -1243,6 +1336,8 @@ void iphone_main(int argc, char *argv[]) {
system("mkdir " SCUMMVM_ROOT_PATH);
system("mkdir " SCUMMVM_SAVE_PATH);
+ chdir("/var/mobile/");
+
g_system = OSystem_IPHONE_create();
assert(g_system);
diff --git a/backends/platform/iphone/osys_iphone.h b/backends/platform/iphone/osys_iphone.h
index af883a62c9..a9a3ddad65 100644
--- a/backends/platform/iphone/osys_iphone.h
+++ b/backends/platform/iphone/osys_iphone.h
@@ -35,14 +35,12 @@
#include <AudioToolbox/AudioQueue.h>
#define AUDIO_BUFFERS 3
-#define WAVE_BUFFER_SIZE 8192
+#define WAVE_BUFFER_SIZE 2048
#define AUDIO_SAMPLE_RATE 44100
#define SCUMMVM_ROOT_PATH "/var/mobile/Library/ScummVM"
#define SCUMMVM_SAVE_PATH SCUMMVM_ROOT_PATH "/Savegames"
-#define SCUMMVM_OLD_SAVE_PATH "/var/root/.scummvm"
#define SCUMMVM_PREFS_PATH SCUMMVM_ROOT_PATH "/Preferences"
-#define SCUMMVM_OLD_PREFS_PATH "/var/root/.scummvmrc"
typedef void (*SoundProc)(void *param, byte *buf, int len);
typedef int (*TimerProc)(int interval);
@@ -61,7 +59,6 @@ protected:
static AQCallbackStruct s_AudioQueue;
static SoundProc s_soundCallback;
static void *s_soundParam;
- static bool s_is113OrHigher;
Common::SaveFileManager *_savefile;
Audio::MixerImpl *_mixer;
@@ -97,6 +94,11 @@ protected:
long _lastSecondaryTap;
int _gestureStartX, _gestureStartY;
bool _mouseClickAndDragEnabled;
+ bool _touchpadModeEnabled;
+ int _lastPadX;
+ int _lastPadY;
+ int _lastDragPosX;
+ int _lastDragPosY;
int _timerCallbackNext;
int _timerCallbackTimer;
@@ -106,6 +108,8 @@ protected:
ScreenOrientation _screenOrientation;
bool _fullScreenIsDirty;
+ FilesystemFactory *_fsFactory;
+
public:
OSystem_IPHONE();
@@ -161,7 +165,7 @@ public:
virtual void quit();
- FilesystemFactory *getFilesystemFactory() { return &POSIXFilesystemFactory::instance(); }
+ FilesystemFactory *getFilesystemFactory() { return _fsFactory; }
virtual void getTimeAndDate(struct tm &t) const;
virtual void setWindowCaption(const char *caption);
@@ -170,9 +174,10 @@ public:
virtual Audio::Mixer *getMixer();
virtual Common::TimerManager *getTimerManager();
- static void migrateApp();
+ void startSoundsystem();
+ void stopSoundsystem();
+
static const char* getConfigPath();
- static const char* getSavePath();
protected:
inline void addDirtyRect(int16 x1, int16 y1, int16 w, int16 h);
@@ -183,6 +188,18 @@ protected:
void suspendLoop();
static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB);
static int timerHandler(int t);
+
+ bool handleEvent_swipe(Common::Event &event, int direction);
+ void handleEvent_keyPressed(Common::Event &event, int keyPressed);
+ void handleEvent_orientationChanged(int orientation);
+
+ bool handleEvent_mouseDown(Common::Event &event, int x, int y);
+ bool handleEvent_mouseUp(Common::Event &event, int x, int y);
+
+ bool handleEvent_secondMouseDown(Common::Event &event, int x, int y);
+ bool handleEvent_secondMouseUp(Common::Event &event, int x, int y);
+
+ bool handleEvent_mouseDragged(Common::Event &event, int x, int y);
};
#endif
diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp
index 463e9d7b2d..610f1d3a42 100644
--- a/backends/platform/null/null.cpp
+++ b/backends/platform/null/null.cpp
@@ -50,13 +50,12 @@
#include "backends/fs/windows/windows-fs-factory.h"
#endif
-
-
class OSystem_NULL : public OSystem {
protected:
Common::SaveFileManager *_savefile;
Audio::MixerImpl *_mixer;
Common::TimerManager *_timer;
+ FilesystemFactory *_fsFactory;
timeval _startTime;
public:
@@ -133,12 +132,23 @@ OSystem_NULL::OSystem_NULL() {
_savefile = 0;
_mixer = 0;
_timer = 0;
+
+ #if defined(__amigaos4__)
+ _fsFactory = new AmigaOSFilesystemFactory();
+ #elif defined(UNIX)
+ _fsFactory = new POSIXFilesystemFactory();
+ #elif defined(WIN32)
+ _fsFactory = new WindowsFilesystemFactory();
+ #else
+ #error Unknown and unsupported FS backend
+ #endif
}
OSystem_NULL::~OSystem_NULL() {
delete _savefile;
delete _mixer;
delete _timer;
+ delete _fsFactory;
}
void OSystem_NULL::initBackend() {
@@ -194,11 +204,11 @@ void OSystem_NULL::initSize(uint width, uint height) {
}
int16 OSystem_NULL::getHeight() {
- return 320;
+ return 200;
}
int16 OSystem_NULL::getWidth() {
- return 200;
+ return 320;
}
void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) {
@@ -327,18 +337,9 @@ void OSystem_NULL::getTimeAndDate(struct tm &t) const {
}
FilesystemFactory *OSystem_NULL::getFilesystemFactory() {
- #if defined(__amigaos4__)
- return &AmigaOSFilesystemFactory::instance();
- #elif defined(UNIX)
- return &POSIXFilesystemFactory::instance();
- #elif defined(WIN32)
- return &WindowsFilesystemFactory::instance();
- #else
- #error Unknown and unsupported backend in OSystem_NULL::getFilesystemFactory
- #endif
+ return _fsFactory;
}
-
OSystem *OSystem_NULL_create() {
return new OSystem_NULL();
}
diff --git a/backends/platform/ps2/rawsavefile.cpp b/backends/platform/ps2/rawsavefile.cpp
index 03270ea9ce..aa3cc57fe7 100644
--- a/backends/platform/ps2/rawsavefile.cpp
+++ b/backends/platform/ps2/rawsavefile.cpp
@@ -31,6 +31,7 @@ RawReadFile::RawReadFile(McAccess *mcAccess) {
_size = -1;
_pos = 0;
_buf = NULL;
+ _eof = false;
}
RawReadFile::~RawReadFile(void) {
@@ -79,12 +80,16 @@ int RawReadFile::bufSeek(int ofs, int whence) {
_pos = 0;
else if (_pos > _size)
_pos = _size;
+
+ _eof = false;
return _pos;
}
int RawReadFile::bufRead(void *dest, int size) {
- if (_pos + size > _size)
+ if (_pos + size > _size) {
size = _size - _pos;
+ _eof = true;
+ }
memcpy(dest, _buf + _pos, size);
_pos += size;
return size;
@@ -94,7 +99,13 @@ int RawReadFile::bufSize(void) const {
return _size;
}
+bool RawReadFile::bufEof(void) const {
+ return _eof;
+}
+void RawReadFile::bufClearErr(void) const {
+ _eof = false;
+}
RawWriteFile::RawWriteFile(McAccess *mcAccess) {
_mcAccess = mcAccess;
diff --git a/backends/platform/ps2/rawsavefile.h b/backends/platform/ps2/rawsavefile.h
index b638d106ab..8e0dba4ab9 100644
--- a/backends/platform/ps2/rawsavefile.h
+++ b/backends/platform/ps2/rawsavefile.h
@@ -40,11 +40,14 @@ public:
int bufTell(void) const;
int bufSeek(int ofs, int whence);
int bufSize(void) const;
+ bool bufEof(void) const;
+ void bufClearErr(void);
protected:
McAccess *_mcAccess;
int _size;
uint8 *_buf;
int _pos;
+ bool _eof;
};
class RawWriteFile {
diff --git a/backends/platform/ps2/savefile.cpp b/backends/platform/ps2/savefile.cpp
index 5ee724cd3f..bfcaf0f57f 100644
--- a/backends/platform/ps2/savefile.cpp
+++ b/backends/platform/ps2/savefile.cpp
@@ -71,7 +71,7 @@ uint32 AutoSaveFile::write(const void *ptr, uint32 size) {
UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess *mcAccess) : RawReadFile(mcAccess) {
_screen = screen;
- _ioFailed = true;
+ _err = true;
if (bufOpen(filename)) {
if ((_size > 8) && (*(uint32 *)_buf == UCL_MAGIC)) {
@@ -82,13 +82,13 @@ UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen, McAccess
free(_buf);
_buf = decBuf;
_size = resSize;
- _ioFailed = false;
+ _err = false;
_pos = 0;
} else
free(decBuf);
}
}
- if (_ioFailed) {
+ if (_err) {
if (_buf)
free(_buf);
_buf = NULL;
@@ -100,36 +100,39 @@ UclInSaveFile::~UclInSaveFile(void) {
_screen->wantAnim(false);
}
-bool UclInSaveFile::ioFailed(void) const {
- return _ioFailed;
+bool UclInSaveFile::err(void) const {
+ return _err;
}
-void UclInSaveFile::clearIOFailed(void) {
- _ioFailed = false;
+void UclInSaveFile::clearErr(void) {
+ _err = false;
+ bufClearErr();
}
bool UclInSaveFile::eos(void) const {
- return bufTell() == bufSize();
+ return bufEof();
}
-uint32 UclInSaveFile::pos(void) const {
+int32 UclInSaveFile::pos(void) const {
return bufTell();
}
-uint32 UclInSaveFile::size(void) const {
+int32 UclInSaveFile::size(void) const {
return bufSize();
}
-void UclInSaveFile::seek(int pos, int whence) {
+bool UclInSaveFile::seek(int pos, int whence) {
bufSeek(pos, whence);
+ return true;
}
uint32 UclInSaveFile::read(void *ptr, uint32 size) {
return (uint32)bufRead(ptr, (int)size);
}
-void UclInSaveFile::skip(uint32 offset) {
+bool UclInSaveFile::skip(uint32 offset) {
bufSeek(offset, SEEK_CUR);
+ return true;
}
UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc) : RawWriteFile(mc) {
@@ -137,7 +140,7 @@ UclOutSaveFile::UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dSc
_system = system;
strcpy(_fileName, filename);
- _ioFailed = !bufOpen(filename);
+ _err = !bufOpen(filename);
_wasFlushed = false;
}
@@ -146,7 +149,7 @@ UclOutSaveFile::~UclOutSaveFile(void) {
if (_pos != 0) {
printf("Engine didn't call SaveFile::flush()\n");
flush();
- if (ioFailed()) {
+ if (err()) {
// unable to save to memory card and it's too late to return an error code to the engine
_system->msgPrintf(5000, "!WARNING!\nCan't write to memory card.\nGame was NOT saved.");
printf("~UclOutSaveFile: Flush failed!\n");
@@ -160,20 +163,20 @@ uint32 UclOutSaveFile::write(const void *ptr, uint32 size) {
return size;
}
-bool UclOutSaveFile::ioFailed(void) const {
- return _ioFailed;
+bool UclOutSaveFile::err(void) const {
+ return _err;
}
-void UclOutSaveFile::clearIOFailed(void) {
- _ioFailed = false;
+void UclOutSaveFile::clearErr(void) {
+ _err = false;
}
-void UclOutSaveFile::flush(void) {
+bool UclOutSaveFile::flush(void) {
if (_pos != 0) {
if (_wasFlushed) {
printf("Multiple calls to UclOutSaveFile::flush!\n");
- _ioFailed = true;
- return;
+ _err = true;
+ return false;
}
uint32 compSize = _pos * 2;
uint8 *compBuf = (uint8*)memalign(64, compSize + 8);
@@ -188,11 +191,12 @@ void UclOutSaveFile::flush(void) {
_pos = compSize + 8;
if (!bufFlush()) {
printf("UclOutSaveFile::flush failed!\n");
- _ioFailed = true;
+ _err = true;
removeFile();
}
_wasFlushed = true;
}
+ return true;
}
/* ----------------------------------------- Glue Classes for POSIX Memory Card Access ----------------------------------------- */
@@ -216,11 +220,11 @@ uint32 Ps2McReadFile::write(const void *src, uint32 len) {
return 0;
}
-uint32 Ps2McReadFile::tell(void) {
+int32 Ps2McReadFile::tell(void) {
return bufTell();
}
-uint32 Ps2McReadFile::size(void) {
+int32 Ps2McReadFile::size(void) {
return bufSize();
}
@@ -253,11 +257,11 @@ uint32 Ps2McWriteFile::write(const void *src, uint32 len) {
return len;
}
-uint32 Ps2McWriteFile::tell(void) {
+int32 Ps2McWriteFile::tell(void) {
return bufTell();
}
-uint32 Ps2McWriteFile::size(void) {
+int32 Ps2McWriteFile::size(void) {
return bufTell();
}
@@ -267,6 +271,3 @@ int Ps2McWriteFile::seek(int32 offset, int origin) {
return 0;
}
-bool Ps2McWriteFile::eof(void) {
- return true;
-}
diff --git a/backends/platform/ps2/savefile.h b/backends/platform/ps2/savefile.h
index 4832b8c3fe..0c0cf922f4 100644
--- a/backends/platform/ps2/savefile.h
+++ b/backends/platform/ps2/savefile.h
@@ -41,14 +41,14 @@ public:
UclOutSaveFile(const char *filename, OSystem_PS2 *system, Gs2dScreen *screen, McAccess *mc);
virtual ~UclOutSaveFile(void);
virtual uint32 write(const void *ptr, uint32 size);
- virtual void flush(void);
- virtual bool ioFailed(void) const;
- virtual void clearIOFailed(void);
+ virtual bool flush(void);
+ virtual bool err(void) const;
+ virtual void clearErr(void);
private:
OSystem_PS2 *_system;
Gs2dScreen *_screen;
- bool _ioFailed, _wasFlushed;
+ bool _err, _wasFlushed;
char _fileName[128];
};
@@ -58,16 +58,16 @@ public:
virtual ~UclInSaveFile(void);
virtual bool eos(void) const;
virtual uint32 read(void *ptr, uint32 size);
- virtual bool ioFailed(void) const;
- virtual void clearIOFailed(void);
- virtual void skip(uint32 offset);
+ virtual bool err(void) const;
+ virtual void clearErr(void);
+ virtual bool skip(uint32 offset);
- virtual uint32 pos(void) const;
- virtual uint32 size(void) const;
- virtual void seek(int pos, int whence = SEEK_SET);
+ virtual int32 pos(void) const;
+ virtual int32 size(void) const;
+ virtual bool seek(int pos, int whence = SEEK_SET);
private:
Gs2dScreen *_screen;
- bool _ioFailed;
+ bool _err;
};
class AutoSaveFile : public Common::OutSaveFile {
@@ -75,9 +75,9 @@ public:
AutoSaveFile(Ps2SaveFileManager *saveMan, const char *filename);
~AutoSaveFile(void);
virtual uint32 write(const void *ptr, uint32 size);
- virtual void flush(void) {}
- virtual bool ioFailed(void) { return false; };
- virtual void clearIOFailed(void) {}
+ virtual bool flush(void) {}
+ virtual bool err(void) const { return false; }
+ virtual void clearErr(void) {}
private:
Ps2SaveFileManager *_saveMan;
char _fileName[256];
@@ -95,8 +95,8 @@ public:
virtual bool open(const char *name);
virtual uint32 read(void *dest, uint32 len);
virtual uint32 write(const void *src, uint32 len);
- virtual uint32 tell(void);
- virtual uint32 size(void);
+ virtual int32 tell(void);
+ virtual int32 size(void);
virtual int seek(int32 offset, int origin);
virtual bool eof(void);
};
@@ -108,10 +108,9 @@ public:
virtual bool open(const char *name);
virtual uint32 read(void *dest, uint32 len);
virtual uint32 write(const void *src, uint32 len);
- virtual uint32 tell(void);
- virtual uint32 size(void);
+ virtual int32 tell(void);
+ virtual int32 size(void);
virtual int seek(int32 offset, int origin);
- virtual bool eof(void);
};
#endif // __PS2_SAVEFILE__
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index 6e9b5980d4..69be0abcb2 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -98,7 +98,20 @@ OSystem_PSP::~OSystem_PSP() {
void OSystem_PSP::initBackend() {
- _savefile = new DefaultSaveFileManager();
+ _savefile = new DefaultSaveFileManager("ms0:/scummvm_savegames");
+
+ const char *savePath = _savefile->getSavePath().c_str();
+
+ //check if the save directory exists
+ SceUID fd = sceIoDopen(savePath);
+ if (fd < 0) {
+ //No? then let's create it.
+ sceIoMkdir(savePath, 0777);
+ } else {
+ //it exists, so close it again.
+ sceIoDclose(fd);
+ }
+
_timer = new DefaultTimerManager();
setTimerCallback(&timer_handler, 10);
diff --git a/backends/platform/psp/osys_psp_gu.cpp b/backends/platform/psp/osys_psp_gu.cpp
index 7e36fe6db0..1aa3bcd438 100644
--- a/backends/platform/psp/osys_psp_gu.cpp
+++ b/backends/platform/psp/osys_psp_gu.cpp
@@ -94,19 +94,23 @@ OSystem_PSP_GU::OSystem_PSP_GU() {
//decompress keyboard data
uLongf kbdSize = KBD_DATA_SIZE;
keyboard_letters = (unsigned char *)memalign(16, KBD_DATA_SIZE);
- assert(Z_OK == uncompress((Bytef *)keyboard_letters, &kbdSize, (const Bytef *)keyboard_letters_compressed, size_keyboard_letters_compressed));
-
+ if (!uncompress((Bytef *)keyboard_letters, &kbdSize, (const Bytef *)keyboard_letters_compressed, size_keyboard_letters_compressed))
+ error("OSystem_PSP_GU: uncompressing keyboard_letters failed");
+
kbdSize = KBD_DATA_SIZE;
keyboard_letters_shift = (unsigned char *)memalign(16, KBD_DATA_SIZE);
- assert(Z_OK == uncompress((Bytef *)keyboard_letters_shift, &kbdSize, (const Bytef *)keyboard_letters_shift_compressed, size_keyboard_letters_shift_compressed));
+ if (!uncompress((Bytef *)keyboard_letters_shift, &kbdSize, (const Bytef *)keyboard_letters_shift_compressed, size_keyboard_letters_shift_compressed))
+ error("OSystem_PSP_GU: uncompressing keyboard_letters_shift failed");
kbdSize = KBD_DATA_SIZE;
keyboard_symbols = (unsigned char *)memalign(16, KBD_DATA_SIZE);
- assert(Z_OK == uncompress((Bytef *)keyboard_symbols, &kbdSize, (const Bytef *)keyboard_symbols_compressed, size_keyboard_symbols_compressed));
+ if (!uncompress((Bytef *)keyboard_symbols, &kbdSize, (const Bytef *)keyboard_symbols_compressed, size_keyboard_symbols_compressed))
+ error("OSystem_PSP_GU: uncompressing keyboard_symbols failed");
kbdSize = KBD_DATA_SIZE;
keyboard_symbols_shift = (unsigned char *)memalign(16, KBD_DATA_SIZE);
- assert(Z_OK == uncompress((Bytef *)keyboard_symbols_shift, &kbdSize, (const Bytef *)keyboard_symbols_shift_compressed, size_keyboard_symbols_shift_compressed));
+ if (!uncompress((Bytef *)keyboard_symbols_shift, &kbdSize, (const Bytef *)keyboard_symbols_shift_compressed, size_keyboard_symbols_shift_compressed))
+ error("OSystem_PSP_GU: uncompressing keyboard_symbols_shift failed");
_keyboardVisible = false;
_clut = (unsigned short*)(((unsigned int)clut256)|0x40000000);
diff --git a/backends/platform/psp/portdefs.h b/backends/platform/psp/portdefs.h
index af772230d7..1708a70c74 100644
--- a/backends/platform/psp/portdefs.h
+++ b/backends/platform/psp/portdefs.h
@@ -43,7 +43,6 @@
#include "trace.h"
-#define SCUMMVM_SAVEPATH "ms0:/scummvm_savegames"
#define BREAKPOINT asm("break\n")
diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp
index d2ed59efbe..94ef63488d 100644
--- a/backends/platform/psp/psp_main.cpp
+++ b/backends/platform/psp/psp_main.cpp
@@ -122,16 +122,6 @@ int main(void)
{
SetupCallbacks();
- //check if the save directory exists
- SceUID fd = sceIoDopen(SCUMMVM_SAVEPATH);
- if (fd < 0) {
- //No? then let's create it.
- sceIoMkdir(SCUMMVM_SAVEPATH, 0777);
- } else {
- //it exists, so close it again.
- sceIoDclose(fd);
- }
-
static char *argv[] = { "scummvm", NULL };
static int argc = sizeof(argv)/sizeof(char *)-1;
diff --git a/backends/platform/sdl/events.cpp b/backends/platform/sdl/events.cpp
index a4863d833b..c2edcf78fb 100644
--- a/backends/platform/sdl/events.cpp
+++ b/backends/platform/sdl/events.cpp
@@ -196,7 +196,9 @@ bool OSystem_SDL::pollEvent(Common::Event &event) {
// Alt-Return and Alt-Enter toggle full screen mode
if (b == Common::KBD_ALT && (ev.key.keysym.sym == SDLK_RETURN
|| ev.key.keysym.sym == SDLK_KP_ENTER)) {
+ beginGFXTransaction();
setFullscreenMode(!_fullscreen);
+ endGFXTransaction();
#ifdef USE_OSD
if (_fullscreen)
displayMessageOnOSD("Fullscreen mode");
diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp
index 4a5c143712..96b74ecba7 100644
--- a/backends/platform/sdl/graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -691,20 +691,14 @@ bool OSystem_SDL::saveScreenshot(const char *filename) {
void OSystem_SDL::setFullscreenMode(bool enable) {
Common::StackLock lock(_graphicsMutex);
+
+ if (_fullscreen == enable)
+ return;
- if (_fullscreen != enable || _transactionMode == kTransactionCommit) {
+ if (_transactionMode == kTransactionCommit) {
assert(_hwscreen != 0);
_fullscreen = enable;
- if (_transactionMode == kTransactionActive) {
- _transactionDetails.fs = enable;
- _transactionDetails.fsChanged = true;
-
- _transactionDetails.needHotswap = true;
-
- return;
- }
-
// Switch between fullscreen and windowed mode by invoking hotswapGFXMode().
// We used to use SDL_WM_ToggleFullScreen() in the past, but this caused various
// problems. E.g. on OS X, it was implemented incorrectly for a long time; on
@@ -713,6 +707,11 @@ void OSystem_SDL::setFullscreenMode(bool enable) {
// So, we just do it "manually" now. There shouldn't be any drawbacks to that
// anyway.
hotswapGFXMode();
+ } else if (_transactionMode == kTransactionActive) {
+ _transactionDetails.fs = enable;
+ _transactionDetails.fsChanged = true;
+
+ _transactionDetails.needHotswap = true;
}
}
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index a8655ef5fd..fdc1ba97f6 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -23,7 +23,16 @@
*
*/
+#if defined(WIN32)
+#include <windows.h>
+#if defined(ARRAYSIZE)
+// winnt.h defines ARRAYSIZE, but we want our own one... - this is needed before including util.h
+#undef ARRAYSIZE
+#endif
+#endif
+
#include "backends/platform/sdl/sdl.h"
+#include "common/archive.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/util.h"
@@ -40,6 +49,7 @@
#define SAMPLES_PER_SEC 22050
//#define SAMPLES_PER_SEC 44100
+
/*
* Include header files needed for the getFilesystemFactory() method.
*/
@@ -52,6 +62,21 @@
#endif
+#if defined(UNIX)
+#ifdef MACOSX
+#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences"
+#else
+#define DEFAULT_CONFIG_FILE ".scummvmrc"
+#endif
+#else
+#define DEFAULT_CONFIG_FILE "scummvm.ini"
+#endif
+
+#if defined(MACOSX) || defined(IPHONE)
+#include "CoreFoundation/CoreFoundation.h"
+#endif
+
+
static Uint32 timer_handler(Uint32 interval, void *param) {
((DefaultTimerManager *)param)->handler();
return interval;
@@ -179,6 +204,7 @@ OSystem_SDL::OSystem_SDL()
_soundMutex(0), _soundCond(0), _soundThread(0),
_soundThreadIsRunning(false), _soundThreadShouldQuit(false),
#endif
+ _fsFactory(0),
_savefile(0),
_mixer(0),
_timer(0),
@@ -196,6 +222,19 @@ OSystem_SDL::OSystem_SDL()
memset(&_mouseCurState, 0, sizeof(_mouseCurState));
_inited = false;
+
+
+ #if defined(__amigaos4__)
+ _fsFactory = new AmigaOSFilesystemFactory();
+ #elif defined(UNIX)
+ _fsFactory = new POSIXFilesystemFactory();
+ #elif defined(WIN32)
+ _fsFactory = new WindowsFilesystemFactory();
+ #elif defined(__SYMBIAN32__)
+ // Do nothing since its handled by the Symbian SDL inheritance
+ #else
+ #error Unknown and unsupported FS backend
+ #endif
}
OSystem_SDL::~OSystem_SDL() {
@@ -237,17 +276,115 @@ Common::SaveFileManager *OSystem_SDL::getSavefileManager() {
}
FilesystemFactory *OSystem_SDL::getFilesystemFactory() {
- #if defined(__amigaos4__)
- return &AmigaOSFilesystemFactory::instance();
- #elif defined(UNIX)
- return &POSIXFilesystemFactory::instance();
- #elif defined(WIN32)
- return &WindowsFilesystemFactory::instance();
- #elif defined(__SYMBIAN32__)
- // Do nothing since its handled by the Symbian SDL inheritance
- #else
- #error Unknown and unsupported backend in OSystem_SDL::getFilesystemFactory
- #endif
+ assert(_fsFactory);
+ return _fsFactory;
+}
+
+void OSystem_SDL::addSysArchivesToSearchSet(Common::SearchSet &s, uint priority) {
+
+#ifdef DATA_PATH
+ // Add the global DATA_PATH to the directory search list
+ // FIXME: We use depth = 4 for now, to match the old code. May want to change that
+ Common::FilesystemNode dataNode(DATA_PATH);
+ if (dataNode.exists() && dataNode.isDirectory()) {
+ Common::ArchivePtr dataArchive(new Common::FSDirectory(dataNode, 4));
+ s.add(DATA_PATH, dataArchive, priority);
+ }
+#endif
+
+#if defined(MACOSX) || defined(IPHONE)
+ // Get URL of the Resource directory of the .app bundle
+ CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
+ if (fileUrl) {
+ // Try to convert the URL to an absolute path
+ UInt8 buf[MAXPATHLEN];
+ if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) {
+ // Success: Add it to the search path
+ Common::String bundlePath((const char *)buf);
+ Common::ArchivePtr bundleArchive(new Common::FSDirectory(bundlePath));
+ s.add("__OSX_BUNDLE__", bundleArchive, priority);
+ }
+ CFRelease(fileUrl);
+ }
+
+#endif
+
+}
+
+
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
+ OSVERSIONINFO win32OsVersion;
+ ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO));
+ win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&win32OsVersion);
+ // Check for non-9X version of Windows.
+ if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
+ // Use the Application Data directory of the user profile.
+ if (win32OsVersion.dwMajorVersion >= 5) {
+ if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile)))
+ error("Unable to access application data directory");
+ } else {
+ if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile)))
+ error("Unable to access user profile directory");
+
+ strcat(configFile, "\\Application Data");
+ CreateDirectory(configFile, NULL);
+ }
+
+ strcat(configFile, "\\ScummVM");
+ CreateDirectory(configFile, NULL);
+ strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
+
+ FILE *tmp = NULL;
+ if ((tmp = fopen(configFile, "r")) == NULL) {
+ // Check windows directory
+ char oldConfigFile[MAXPATHLEN];
+ GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
+ strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
+ if ((tmp = fopen(oldConfigFile, "r"))) {
+ strcpy(configFile, oldConfigFile);
+
+ fclose(tmp);
+ }
+ } else {
+ fclose(tmp);
+ }
+ } else {
+ // Check windows directory
+ GetWindowsDirectory(configFile, MAXPATHLEN);
+ strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
+ }
+#elif defined(UNIX)
+ // On UNIX type systems, by default we store the config file inside
+ // to the HOME directory of the user.
+ //
+ // GP2X is Linux based but Home dir can be read only so do not use
+ // it and put the config in the executable dir.
+ //
+ // On the iPhone, the home dir of the user when you launch the app
+ // from the Springboard, is /. Which we don't want.
+ const char *home = getenv("HOME");
+ if (home != NULL && strlen(home) < MAXPATHLEN)
+ snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE);
+ else
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+#else
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+#endif
+
+ return configFile;
+}
+
+Common::SeekableReadStream *OSystem_SDL::openConfigFileForReading() {
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForReading();
+}
+
+Common::WriteStream *OSystem_SDL::openConfigFileForWriting() {
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForWriting();
}
void OSystem_SDL::setWindowCaption(const char *caption) {
@@ -332,15 +469,21 @@ void OSystem_SDL::quit() {
}
void OSystem_SDL::setupIcon() {
- int w, h, ncols, nbytes, i;
- unsigned int rgba[256], icon[32 * 32];
- unsigned char mask[32][4];
+ int x, y, w, h, ncols, nbytes, i;
+ unsigned int rgba[256];
+ unsigned int *icon;
sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes);
- if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) {
- warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes);
+ if ((w > 512) || (h > 512) || (ncols > 255) || (nbytes > 1)) {
+ warning("Could not load the built-in icon (%d %d %d %d)", w, h, ncols, nbytes);
return;
}
+ icon = (unsigned int*)malloc(w*h*sizeof(unsigned int));
+ if (!icon) {
+ warning("Could not allocate temp storage for the built-in icon");
+ return;
+ }
+
for (i = 0; i < ncols; i++) {
unsigned char code;
char color[32];
@@ -354,26 +497,27 @@ void OSystem_SDL::setupIcon() {
sscanf(color + 1, "%06x", &col);
col |= 0xFF000000;
} else {
- warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]);
+ warning("Could not load the built-in icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]);
+ free(icon);
return;
}
rgba[code] = col;
}
- memset(mask, 0, sizeof(mask));
- for (h = 0; h < 32; h++) {
- const char *line = scummvm_icon[1 + ncols + h];
- for (w = 0; w < 32; w++) {
- icon[w + 32 * h] = rgba[(int)line[w]];
- if (rgba[(int)line[w]] & 0xFF000000) {
- mask[h][w >> 3] |= 1 << (7 - (w & 0x07));
- }
+ for (y = 0; y < h; y++) {
+ const char *line = scummvm_icon[1 + ncols + y];
+ for (x = 0; x < w; x++) {
+ icon[x + w * y] = rgba[(int)line[x]];
}
}
- SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
- SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask);
+ SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, w, h, 32, w * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
+ if (!sdl_surf) {
+ warning("SDL_CreateRGBSurfaceFrom(icon) failed");
+ }
+ SDL_WM_SetIcon(sdl_surf, NULL);
SDL_FreeSurface(sdl_surf);
+ free(icon);
}
OSystem::MutexRef OSystem_SDL::createMutex(void) {
@@ -412,7 +556,7 @@ void OSystem_SDL::mixerProducerThread() {
// Generate samples and put them into the next buffer
nextSoundBuffer = _activeSoundBuf ^ 1;
_mixer->mixCallback(_soundBuffers[nextSoundBuffer], _soundBufSize);
-
+
// Swap buffers
_activeSoundBuf = nextSoundBuffer;
}
@@ -456,7 +600,7 @@ void OSystem_SDL::deinitThreadedMixer() {
SDL_CondBroadcast(_soundCond);
SDL_WaitThread(_soundThread, NULL);
- // Kill the mutex & cond variables.
+ // Kill the mutex & cond variables.
// Attention: AT this point, the mixer callback must not be running
// anymore, else we will crash!
SDL_DestroyMutex(_soundMutex);
@@ -479,10 +623,10 @@ void OSystem_SDL::mixCallback(void *arg, byte *samples, int len) {
// Lock mutex, to ensure our data is not overwritten by the producer thread
SDL_LockMutex(this_->_soundMutex);
-
+
// Copy data from the current sound buffer
memcpy(samples, this_->_soundBuffers[this_->_activeSoundBuf], len);
-
+
// Unlock mutex and wake up the produced thread
SDL_UnlockMutex(this_->_soundMutex);
SDL_CondSignal(this_->_soundCond);
@@ -542,7 +686,7 @@ void OSystem_SDL::setupMixer() {
// even if it didn't. Probably only happens for "weird" rates, though.
_samplesPerSec = obtained.freq;
debug(1, "Output sample rate: %d Hz", _samplesPerSec);
-
+
// Tell the mixer that we are ready and start the sound processing
_mixer->setOutputRate(_samplesPerSec);
_mixer->setReady(true);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 3fbfa8ba0d..3639d61c3a 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -212,6 +212,10 @@ public:
virtual Common::SaveFileManager *getSavefileManager();
virtual FilesystemFactory *getFilesystemFactory();
+ virtual void addSysArchivesToSearchSet(Common::SearchSet &s, uint priority = 0);
+
+ virtual Common::SeekableReadStream *openConfigFileForReading();
+ virtual Common::WriteStream *openConfigFileForWriting();
protected:
bool _inited;
@@ -400,14 +404,13 @@ protected:
void deinitThreadedMixer();
#endif
-
+ FilesystemFactory *_fsFactory;
Common::SaveFileManager *_savefile;
Audio::MixerImpl *_mixer;
SDL_TimerID _timerID;
Common::TimerManager *_timer;
-
protected:
void addDirtyRgnAuto(const byte *buf);
void makeChecksums(const byte *buf);
diff --git a/backends/platform/symbian/AdaptAllMMPs.pl b/backends/platform/symbian/AdaptAllMMPs.pl
index b576bb3993..d7b5642f1c 100644
--- a/backends/platform/symbian/AdaptAllMMPs.pl
+++ b/backends/platform/symbian/AdaptAllMMPs.pl
@@ -27,7 +27,7 @@ chdir("../../../");
"mmp/scummvm_sword1.mmp",
"mmp/scummvm_sword2.mmp",
"mmp/scummvm_touche.mmp",
-
+ "mmp/scummvm_tinsel.mmp",
# Target Platform Project Files
"S60/ScummVM_S60.mmp",
@@ -83,6 +83,9 @@ my @excludes_graphics = (
"iff.cpp"
);
+my @excludes_gui = (
+);
+
# the USE_ARM_* defines not parsed correctly, exclude manually:
my @excludes_scumm = (
".*ARM.*", # the *ARM.s files are added in .mpp files based on WINS/ARM build!
@@ -95,7 +98,7 @@ my @excludes_scumm = (
#arseModule(mmpStr, dirStr, ifdefArray, [exclusionsArray])
ParseModule("_base", "base", \@section_empty); # now in ./TRG/ScummVM_TRG.mmp, these never change anyways...
ParseModule("_base", "common", \@section_empty);
-ParseModule("_base", "gui", \@section_empty);
+ParseModule("_base", "gui", \@section_empty, \@excludes_gui);
ParseModule("_base", "graphics", \@section_empty, \@excludes_graphics);
ParseModule("_base", "sound", \@section_empty, \@excludes_snd);
@@ -103,22 +106,23 @@ chdir("engines/");
ParseModule("_scumm", "scumm", \@sections_scumm, \@excludes_scumm );
ParseModule("_queen", "queen", \@section_empty);
ParseModule("_agos", "agos", \@section_empty);
-ParseModule("_sky", "sky", \@section_empty);
-ParseModule("_gob", "gob", \@section_empty);
+ParseModule("_sky", "sky", \@section_empty);
+ParseModule("_gob", "gob", \@section_empty);
ParseModule("_saga", "saga", \@section_empty);
ParseModule("_kyra", "kyra", \@section_empty);
ParseModule("_sword1", "sword1", \@section_empty);
ParseModule("_sword2", "sword2", \@section_empty);
ParseModule("_lure", "lure", \@section_empty);
ParseModule("_cine", "cine", \@section_empty);
-ParseModule("_agi", "agi", \@section_empty);
+ParseModule("_agi", "agi", \@section_empty);
ParseModule("_touche", "touche", \@section_empty);
ParseModule("_parallaction","parallaction",\@section_empty);
ParseModule("_cruise", "cruise", \@section_empty);
ParseModule("_drascula","drascula", \@section_empty);
ParseModule("_igor", "igor", \@section_empty);
ParseModule("_made", "made", \@section_empty);
-ParseModule("_m4", "m4", \@section_empty);
+ParseModule("_m4", "m4", \@section_empty);
+ParseModule("_tinsel", "tinsel", \@section_empty);
print "
=======================================================================================
Done. Enjoy :P
diff --git a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl
index 94edbf4fcf..ba8afe5084 100644
--- a/backends/platform/symbian/BuildPackageUpload_AllVersions.pl
+++ b/backends/platform/symbian/BuildPackageUpload_AllVersions.pl
@@ -443,6 +443,10 @@ my $header = "
PrintMessage("Cleaning for $Target") if (!$ReallyQuiet);
system("bldmake bldfiles > NUL 2> NUL");
PrintErrorMessage("'bldmake bldfiles' exited with value " . ($? >> 8)) if ($? >> 8);
+
+ system("abld MAKEFILE $TargetName > NUL 2> NUL");
+ PrintErrorMessage("'abld MAKEFILE $TargetName' exited with value " . ($? >> 8)) if ($? >> 8);
+
system("abld CLEAN $TargetName UREL > NUL 2> NUL");
PrintErrorMessage("'abld CLEAN $TargetName urel' exited with value " . ($? >> 8)) if ($? >> 8);
# remove file so we are sure that after .lib generation we have a fresh copy!
@@ -455,10 +459,10 @@ my $header = "
my $OldSize = (-s $build_log_err);
$Redirection = ($RedirectSTDERR ? "2>> $build_log_err" : "");
- system("abld BUILD $TargetName UREL $Redirection >> $build_log_out");
+ system("abld TARGET $TargetName UREL $Redirection >> $build_log_out");
$OK = 0 if ($? >> 8);
# print " STDERR: ".((-s $build_log_err)-$OldSize)." bytes output written to $build_log_err\n+--------------------------------------------------------------------------------------\n" if ($OldSize != (-s $build_log_err));
- PrintErrorMessage("'abld BUILD $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8);
+ PrintErrorMessage("'abld TARGET $TargetName UREL' exited with value " . ($? >> 8)) if ($? >> 8);
return 0 if (!$OK); # ABLD always returns ok :( grr
PrintMessage("Done.") if (!$ReallyQuiet);
@@ -475,7 +479,7 @@ my $header = "
}
else
{
- PrintErrorMessage("'abld BUILD $TargetName UREL' apparently failed.");
+ PrintErrorMessage("'abld TARGET $TargetName UREL' apparently failed.");
if ($HaltOnError)
{
PrintErrorMessage("Halting on error as requested!");
diff --git a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
index 22846f45dd..8ba743674d 100644
--- a/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
+++ b/backends/platform/symbian/BuildPackageUpload_LocalSettings.pl
@@ -2,16 +2,16 @@
##################################################################################################################
@WorkingEngines = qw(
- scumm agos sky queen gob saga
- kyra lure agi
+ scumm agos sky queen gob saga drascula
+ kyra lure agi touche parallaction cine
+ cruise igor made m4 tinsel sword1 sword2
);
+
@TestingEngines = qw(
- cine cruise touche parallaction
- drascula igor made m4
+
);
- @BrokenEngines = qw(
- sword1
- sword2
+
+ @BrokenEngines = qw(
);
@EnablableEngines = (@WorkingEngines, @TestingEngines);
@@ -29,21 +29,8 @@
);
# these are normally enabled for each variation
- $DefaultFeatures = qw(zlib mad tremor);
- #$DefaultFeatures = qw(zlib mad tremor);
-
-
- # you can use these below for speed & clarity or override with custom settings
- $DefaultTopMacros = "
- MACRO USE_ZLIB // LIB:zlib.lib
- //MACRO USE_MAD // LIB:libmad.lib
- MACRO USE_TREMOR // LIB:libtremor.lib
- ";
-
- $DefaultBottomMacros = "
- MACRO DISABLE_SWORD1 // LIB:scummvm_sword1.lib
- MACRO DISABLE_SWORD2 // LIB:scummvm_sword2.lib
- ";
+ #$DefaultFeatures = qw(zlib,mad);
+ $DefaultFeatures = qw(zlib,mad,tremor);
##################################################################################################################
##
@@ -187,6 +174,44 @@
# now you can add $VariationSets only built on this PC below this line :)
}
+ elsif ($ENV{'COMPUTERNAME'} eq "EMBEDDEV-LAPE") #################################################################
+ {
+ $Producer = "AnotherGuest";
+ $RedirectSTDERR = 1;
+ $HaltOnError = 0;
+ $SkipExistingPackages = 1;
+ $ReallyQuiet = 1;
+
+ #$FTP_Host = "host.com";
+ #$FTP_User = "ag@host.com";
+ #$FTP_Pass = "password";
+ #$FTP_Dir = "cvsbuilds";
+
+ #$SDK_RootDirs{'UIQ2'}= "D:\\UIQ2";
+ $SDK_RootDirs{'UIQ3'}= "G:\\UIQ3";
+ #$SDK_RootDirs{'S60v1'}= "D:\\S60v1";
+ #$SDK_RootDirs{'S60v2'}= "D:\\S60v2";
+ $SDK_RootDirs{'S60v3'}= "G:\\S60_3rd_FP1";
+ #$SDK_RootDirs{'S80'}= "D:\\S80";
+ #$SDK_RootDirs{'S90'}= "D:\\S90";
+ $ECompXL_BinDir= "D:\\ECompXL\\";
+ if (0) # so we can turn them on/off easily
+ {
+# $SDK_LibraryDirs{'ALL'}{'zlib.lib'} = "C:\\S\\zlib-1.2.2\\epoc";
+# $SDK_LibraryDirs{'ALL'}{'libmad.lib'} = "C:\\S\\libmad-0.15.1b\\group";
+# $SDK_LibraryDirs{'ALL'}{'libtremor.lib'}= "C:\\tremor\\epoc";
+ $SDK_LibraryDirs{'UIQ2'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\UIQ";
+ $SDK_LibraryDirs{'S60v1'}{'esdl.lib'} = $SDK_LibraryDirs{'S60v2'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S60";
+ $SDK_LibraryDirs{'S80'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S80";
+ $SDK_LibraryDirs{'S90'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S90";
+ $SDK_LibraryDirs{'S60v3'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\S60\\S60V3";
+ $SDK_LibraryDirs{'UIQ3'}{'esdl.lib'} = "E:\\WICKED\\ESDL\\epoc\\UIQ\\UIQ3";
+ #$SDK_LibraryDirs{'ALL'}{'libmpeg2.lib'} = "C:\\S\\mpeg2dec-0.4.0\\epoc";
+ }
+
+ # now you can add $VariationSets only built on this PC below this line :)
+
+ }
else #########################################################################################################
{
print "ERROR: Computer name ".$ENV{'COMPUTERNAME'}." not recognized! Plz edit _LocalSettings.pl!";
@@ -246,15 +271,11 @@
}
# below here you could specify weird & experimental combinations, non-ready engines
- # a small version of the saga engine, because it is so big (no tremor,mad,zlib)
- #$VariationSets{'ALL'}{'saga_mini'} = "saga";
+ # Separate version for the broken sword engines (1&2)
+ $VariationSets{'ALL'}{'brokensword'} = "$DefaultFeatures sword1 sword2";
- # a smaller version of scumm without support for v7, v8 and HE games
- #$VariationSets{'ALL'}{'scumm_no78he'} = "$DefaultFeatures scumm";
-
- # maybe you feel lucky and want to test the sword engines? :P
- #$VariationSets{'S60v2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2";
- #$VariationSets{'UIQ2'}{'test_sword'} = "$DefaultFeatures mpeg2 sword1 sword2";
+ # Separate version for Scumm games (COMI) since memory usage might be high
+ $VariationSets{'ALL'}{'scumm'} = "$DefaultFeatures scumm scumm_7_8 he";
# for mega-fast-testing only plz! Warning: contains to engines!
#$VariationSets{'ALL'}{'fast_empty'} = "";
diff --git a/backends/platform/symbian/README b/backends/platform/symbian/README
index 8ab729a4d0..1e011ec4a1 100644
--- a/backends/platform/symbian/README
+++ b/backends/platform/symbian/README
@@ -1,33 +1,45 @@
ScummVM - ScummVM ported to EPOC/SymbianOS
- Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson
- Copyright (C) 2007 Lars 'AnotherGuest' Persson
- Copyright (C) 2007 Jurgen 'SumthinWicked' Braam
- Copyright (C) 2007 ScummVM Team
+ Copyright (C) 2008 ScummVM Team
+ Copyright (C) 2003-2008 Lars 'AnotherGuest' Persson
+ Copyright (C) 2002008 Jurgen 'SumthinWicked' Braam
+ Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson
$Id$
+Using parts of snprintf.c by
+Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
+Copyright © 1999,2000,2001,2002 Mark Martinec. All rights reserved.
+under these conditions:
+"Terms and conditions ...
+
+This program is free software; it is dual licensed, the terms of the "Frontier Artistic License" or
+the "GNU General Public License" can be chosen at your discretion.
+The chosen license then applies solely and in its entirety.
+Both licenses come with this Kit."
+
+
About ScummVM
--------------
The original ports (uptil 0.7.1) were made by Andreas Karlsson and Lars Persson.
The main transition to 0.8.0CVS and all relevant changes were done by Jurgen Braam.
- Jurgen and Lars have successfully transfered all needed changes into CVS, with additional helpful tools for Symbian OS
+ Jurgen and Lars have successfully transfered all needed changes into CVS/SVN, with additional helpful tools for Symbian OS
- Release version: 0.10.0
+ Release version: 0.12.0
* This version is only supported on Symbian OS 9 devices due to compiler constraints for older devices. (That means UIQ3 and S60V3 devices)
- * Updated to SDL version 1.2.11 (previous version used was 1.2.8)
+ * Updated to SDL version 1.2.13 (previous version used was 1.2.2)
* Information about S60 devices can be found here http://wiki.scummvm.org/index.php/SymbianOS_S60
* Information about UIQ devices can be found here http://wiki.scummvm.org/index.php/SymbianOS_UIQ
* Best source of general information is the ScummVM forum, http://forums.scummvm.org
- * SVN builds (not frequently updated) can be found at http://anotherguest.k0.se
+ * SVN builds (not frequently updated) can be found at http://www.anotherguest.se
Games supported
---------------
The Symbian port of ScummVM supports all but Sword1 & 2 games. Some games might not run properly due to screenresolution or memory constraints.
-
+ Minimum free memory requirement is about 12MB to be able to start and run ScummVM, this is enough for most older games, but newer more resource hungry games, might require more.
Building ScummVM
---------------------
@@ -38,7 +50,7 @@ Building ScummVM
Lets just say the framework needs quite some time to set up and takes a while
to get used to. If you choose to continue you will need the following items:
- - UIQ 3.0 SDK (To build for UIQ3 devices)
+ - UIQ 3.x SDK (To build for UIQ3 devices)(Build scripts in SDK need tweaking in order to build scummvm since Symbian OS GCCE never builds as large projects as ScummVM before)
- UIQ 2.1 SDK (To build for UIQ2 devices);
http://www.symbian.com/developer/sdks_uiq.asp
@@ -72,8 +84,7 @@ Building ScummVM
http://flac.sourceforge.net/
- libmpeg2, a free MPEG-2 video stream decoder
- http://libmpeg2.sourceforge.net/
-
+ http://libmpeg2.sourceforge.net
Compiling ScummVM
-----------------
@@ -89,7 +100,7 @@ Building ScummVM
PETRAN.EXE will be the executable that is started.
- SDL: the latest version of SDL at this point in time is 1.2.12. This version
+ SDL: the latest version of SDL at this point in time is 1.2.13. This version
works great for compiling on other platforms.
zlib: the zlib-x.x.x.tar.gz does not come with UIQ .mpp build files, that's why
diff --git a/backends/platform/symbian/S60/ScummVM_S60.mmp.in b/backends/platform/symbian/S60/ScummVM_S60.mmp.in
index 099b33ed95..35632d9c95 100644
--- a/backends/platform/symbian/S60/ScummVM_S60.mmp.in
+++ b/backends/platform/symbian/S60/ScummVM_S60.mmp.in
@@ -93,6 +93,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg
index bf3c69ae08..91649727df 100644
--- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg
+++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v1.pkg
@@ -16,7 +16,7 @@
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;
; $URL:$
-; $Id:$
+; $Id$
;
;
@@ -28,7 +28,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM S60v1"},(0x101f9b57),0,120,0
+#{"ScummVM S60v1"},(0x101f9b57),0,130,0
; Platform type
(0x101F6F88), 0, 0, 0, {"Series60ProductID"}
diff --git a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg
index 3afb7a094c..4547af0597 100644
--- a/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg
+++ b/backends/platform/symbian/S60/scummvm-CVS-SymbianS60v2.pkg
@@ -27,7 +27,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM S60v2"},(0x101f9b57),0,120,0
+#{"ScummVM S60v2"},(0x101f9b57),0,130,0
; Platform type
(0x101F6F88), 0, 0, 0, {"Series60ProductID"}
@@ -52,6 +52,7 @@
"..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt"
"..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl"
"..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat"
+"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat"
; Config/log files: 'empty' will automagically be removed on uninstall
""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL
diff --git a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
index 3fea916e43..fae74a425a 100644
--- a/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
+++ b/backends/platform/symbian/S60v3/ScummVM_S60v3.mmp.in
@@ -50,7 +50,7 @@ LANG SC
END
EPOCSTACKSIZE 80000
-EPOCHEAPSIZE 3000000 64000000
+EPOCHEAPSIZE 5000000 64000000
START BITMAP ScummVM.mbm
TARGETPATH \Resource\Apps
@@ -116,6 +116,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
index a7126db4c8..1898ac1b58 100644
--- a/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
+++ b/backends/platform/symbian/S60v3/scummvm-CVS-SymbianS60v3.pkg
@@ -16,7 +16,7 @@
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;
; $URL:$
-; $Id:$
+; $Id$
;
;
@@ -34,7 +34,7 @@
:"ScummVM"
; UID is the app's UID
-#{"ScummVM S60v3"},(0xA0000657),0,120,0
+#{"ScummVM S60v3"},(0xA0000657),0,13,0
;Supports Series 60 v 3.0
[0x101F7961], 0, 0, 0, {"Series60ProductID"}
@@ -63,6 +63,7 @@
"..\..\..\..\dists\engine-data\sky.cpt"-"c:\data\scummvm\sky.cpt"
"..\..\..\..\dists\engine-data\igor.tbl"-"c:\data\scummvm\igor.tbl"
"..\..\..\..\dists\engine-data\lure.dat"-"c:\data\scummvm\lure.dat"
+"..\..\..\..\dists\engine-data\drascula.dat"-"c:\data\scummvm\drascula.dat"
; Config/log files: 'empty' will automagically be removed on uninstall
""-"c:\data\scummvm\scummvm.ini",FILENULL
diff --git a/backends/platform/symbian/S80/ScummVM_S80.mmp.in b/backends/platform/symbian/S80/ScummVM_S80.mmp.in
index 95879dd2af..1c8076fdc3 100644
--- a/backends/platform/symbian/S80/ScummVM_S80.mmp.in
+++ b/backends/platform/symbian/S80/ScummVM_S80.mmp.in
@@ -91,6 +91,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg
index 94d457b93a..c6b3e6f82f 100644
--- a/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg
+++ b/backends/platform/symbian/S80/scummvm-CVS-SymbianS80.pkg
@@ -28,7 +28,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM S80"},(0x101f9b57),0,120,0
+#{"ScummVM S80"},(0x101f9b57),0,130,0
; Platform type -- disabled: seems to be causing trouble
;(0x101F8ED2), 0, 0, 0, {"Series80ProductID"}
@@ -53,6 +53,7 @@
"..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt"
"..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl"
"..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat"
+"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat"
; Config/log files: 'empty' will automagically be removed on uninstall
""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL
diff --git a/backends/platform/symbian/S90/Scummvm_S90.mmp.in b/backends/platform/symbian/S90/Scummvm_S90.mmp.in
index 47a3d9a1d4..8ace71b190 100644
--- a/backends/platform/symbian/S90/Scummvm_S90.mmp.in
+++ b/backends/platform/symbian/S90/Scummvm_S90.mmp.in
@@ -91,6 +91,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg
index ca7f08d85f..b578019979 100644
--- a/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg
+++ b/backends/platform/symbian/S90/scummvm-CVS-SymbianS90.pkg
@@ -28,7 +28,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM S90"},(0x101f9b57),0,120,0
+#{"ScummVM S90"},(0x101f9b57),0,130,0
; Platform type -- disabled: seems to be causing trouble
;(0x101FBE04), 0, 0, 0, {"Series90ProductID"}
@@ -53,6 +53,7 @@
"..\..\..\..\dists\engine-data\sky.cpt"-"!:\system\apps\scummvm\sky.cpt"
"..\..\..\..\dists\engine-data\igor.tbl"-"!:\system\apps\scummvm\igor.tbl"
"..\..\..\..\dists\engine-data\lure.dat"-"!:\system\apps\scummvm\lure.dat"
+"..\..\..\..\dists\engine-data\drascula.dat"-"!:\system\apps\scummvm\drascula.dat"
; Config/log files: 'empty' will automagically be removed on uninstall
""-"!:\system\apps\ScummVM\scummvm.ini",FILENULL
diff --git a/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in b/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in
index e9dff7b94f..9fab248799 100644
--- a/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in
+++ b/backends/platform/symbian/UIQ2/ScummVM_UIQ2.mmp.in
@@ -89,6 +89,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg
index aca927eadd..a8b02d4099 100644
--- a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg
+++ b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2.pkg
@@ -16,7 +16,7 @@
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;
; $URL:$
-; $Id:$
+; $Id$
;
;
@@ -28,7 +28,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM UIQ2"},(0x101f9b57),0,100,0
+#{"ScummVM UIQ2"},(0x101f9b57),0,130,0
; Platform type
(0x101F617B), 2, 0, 0, {"UIQ20ProductID"}
diff --git a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg
index ecca51bd26..2d08bd01b2 100644
--- a/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg
+++ b/backends/platform/symbian/UIQ2/scummvm-CVS-SymbianUIQ2_SE.pkg
@@ -6,7 +6,7 @@
;&EN
; UID is the app's UID
-#{"ScummVM SE"},(0x101f9b57),0,110,0
+#{"ScummVM SE"},(0x101f9b57),0,130,0
; Platform type
(0x101F617B), 2, 0, 0, {"UIQ20ProductID"}
diff --git a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
index 0013d061ca..6053a72182 100644
--- a/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
+++ b/backends/platform/symbian/UIQ3/ScummVM_UIQ3.mmp.in
@@ -51,7 +51,7 @@ LANG SC
END
EPOCSTACKSIZE 80000
-EPOCHEAPSIZE 3000000 64000000
+EPOCHEAPSIZE 5000000 64000000
START BITMAP ScummVM.mbm
TARGETPATH \Resource\Apps
@@ -117,6 +117,7 @@ SOURCE backends\platform\symbian\src\ScummApp.cpp
SOURCE gui\Key.cpp
SOURCE gui\KeysDialog.cpp
SOURCE gui\Actions.cpp
+SOURCE gui\Dialog.cpp
// Special for graphics
source graphics\iff.cpp
diff --git a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
index 5d6ce01525..cdeb83f192 100644
--- a/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
+++ b/backends/platform/symbian/UIQ3/scummvm-CVS-SymbianUIQ3.pkg
@@ -16,7 +16,7 @@
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;
; $URL:$
-; $Id:$
+; $Id$
;
;
@@ -32,7 +32,7 @@
:"ScummVM"
; UID is the app's UID
-#{"ScummVM UIQ3"},(0xA0000657),0,120,0
+#{"ScummVM UIQ3"},(0xA0000657),0,13,0
; ProductID for UIQ 3.0
; Product/platform version UID, Major, Minor, Build, Product ID
@@ -61,6 +61,7 @@
"..\..\..\..\dists\engine-data\sky.cpt"-"c:\shared\scummvm\sky.cpt"
"..\..\..\..\dists\engine-data\igor.tbl"-"c:\shared\scummvm\igor.tbl"
"..\..\..\..\dists\engine-data\lure.dat"-"c:\shared\scummvm\lure.dat"
+"..\..\..\..\dists\engine-data\drascula.dat"-"c:\shared\scummvm\drascula.dat"
; Config/log files: 'empty' will automagically be removed on uninstall
""-"c:\shared\scummvm\scummvm.ini",FILENULL
diff --git a/backends/platform/symbian/mmp/scummvm_base.mmp.in b/backends/platform/symbian/mmp/scummvm_base.mmp.in
index d1c8878d4b..3277e34ba3 100644
--- a/backends/platform/symbian/mmp/scummvm_base.mmp.in
+++ b/backends/platform/symbian/mmp/scummvm_base.mmp.in
@@ -85,7 +85,6 @@ SOURCEPATH ..\..\..\..\gui
//SOURCE KeysDialog.cpp
//SOURCE Actions.cpp
-
SOURCEPATH ..\..\..\..\sound
//START_AUTO_OBJECTS_SOUND_//
@@ -108,7 +107,8 @@ SOURCE backends\saves\savefile.cpp
SOURCE backends\saves\default\default-saves.cpp
SOURCE backends\saves\compressed\compressed-saves.cpp
SOURCE engines\engine.cpp
-
-
-// backend specific includes
+SOURCE engines\dialogs.cpp
+SOURCE backends\fs\abstract-fs.cpp
+SOURCE backends\fs\symbian\symbianstream.cpp
// backend specific includes
+
diff --git a/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
new file mode 100644
index 0000000000..3f68ec086e
--- /dev/null
+++ b/backends/platform/symbian/mmp/scummvm_tinsel.mmp.in
@@ -0,0 +1,56 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
+ * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
+ * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
+ * Copyright (C) 2005-2006 The ScummVM project
+ *
+ * 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.
+ *
+ */
+
+//
+// EPOC MMP makefile project for ScummVM
+//
+
+// *** Definitions
+
+TARGET scummvm_tinsel.lib
+TARGETTYPE lib
+OPTION MSVC /QIfist /Ob1 /Oy /GF // /QIfist disables use of __ftol2 to avoid linker probs with MS libc: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcrefQIfistSuppress_ftol.asp
+OPTION GCC -Wno-multichar -Wno-reorder // don't optimize for ARM, platform way too sensitive for that :( just turn off some common warnings
+OPTION GCCE -Wno-multichar -Wno-reorder -Wno-unused -Wno-format -fsigned-char
+ALWAYS_BUILD_AS_ARM
+
+//START_AUTO_MACROS_SLAVE//
+
+// empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_MACROS_SLAVE//
+
+// *** SOURCE files
+
+SOURCEPATH ..\..\..\..\engines\tinsel
+
+//START_AUTO_OBJECTS_TINSEL_//
+
+ // empty base file, will be updated by Perl build scripts
+
+//STOP_AUTO_OBJECTS_TINSEL_//
+
+// *** Include paths
+
+USERINCLUDE ..\..\..\..\engines
+USERINCLUDE ..\..\..\.. ..\..\..\..\common ..\..\..\..\gui ..\..\..\..\sound ..\src
+SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\src
diff --git a/backends/platform/symbian/src/SymbianActions.cpp b/backends/platform/symbian/src/SymbianActions.cpp
index 8fc35e9f8d..e71b242329 100644
--- a/backends/platform/symbian/src/SymbianActions.cpp
+++ b/backends/platform/symbian/src/SymbianActions.cpp
@@ -129,17 +129,20 @@ void SymbianActions::initInstanceGame() {
bool is_simon = (strncmp(gameid.c_str(), "simon", 5) == 0);
bool is_sword1 = (gameid == "sword1");
bool is_sword2 = (strcmp(gameid.c_str(), "sword2") == 0);
- bool is_sky = (strncmp(gameid.c_str(), "sky", 3) == 0);
- bool is_saga = (gameid == "saga");
+ bool is_queen = (gameid == "queen");
+ bool is_sky = (gameid == "sky");
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
- bool is_queen = (strncmp(gameid.c_str(), "queen", 5) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
- bool is_kyra = (gameid == "kyra1");
+ bool is_saga = (gameid == "saga");
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
bool is_agi = (gameid == "agi");
bool is_parallaction = (gameid == "parallaction");
+ bool is_lure = (gameid == "lure");
+ bool is_feeble = (gameid == "feeble");
+ bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0);
Actions::initInstanceGame();
@@ -150,16 +153,16 @@ void SymbianActions::initInstanceGame() {
// Save
- if (is_simon || is_sword2 || is_gob || is_kyra || is_touche)
+ if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble)
_action_enabled[ACTION_SAVE] = false;
else {
_action_enabled[ACTION_SAVE] = true;
if (is_queen) {
- _key_action[ACTION_SAVE].setKey(Common::ASCII_F5, Common::KEYCODE_F5); // F1 key for FOTAQ
+ _key_action[ACTION_SAVE].setKey(Common::ASCII_F1, Common::KEYCODE_F1); // F1 key for FOTAQ
} else if (is_sky) {
_key_action[ACTION_SAVE].setKey(Common::ASCII_F5, Common::KEYCODE_F5);
- } else if (is_cine) {
+ } else if (is_cine || is_drascula) {
_key_action[ACTION_SAVE].setKey(Common::ASCII_F10, Common::KEYCODE_F10); // F10
} else if (is_agi) {
_key_action[ACTION_SAVE].setKey(Common::ASCII_ESCAPE, Common::KEYCODE_ESCAPE);
@@ -175,7 +178,8 @@ void SymbianActions::initInstanceGame() {
// Skip text
if (!is_cine && !is_parallaction)
_action_enabled[ACTION_SKIP_TEXT] = true;
- if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_saga || is_kyra || is_touche)
+ if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob ||
+ is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula)
_key_action[ACTION_SKIP_TEXT].setKey(Common::KEYCODE_ESCAPE, Common::KEYCODE_ESCAPE); // Escape key
else {
_key_action[ACTION_SKIP_TEXT].setKey(SDLK_PERIOD);
diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp
index e3a4027d79..23876c5ec1 100644
--- a/backends/platform/symbian/src/SymbianOS.cpp
+++ b/backends/platform/symbian/src/SymbianOS.cpp
@@ -24,12 +24,15 @@
#include <eikenv.h> // for CEikonEnv::Static() @ Symbian::FatalError()
#include <sdlapp.h> // for CSDLApp::GetExecutablePathCStr() @ Symbian::GetExecutablePath()
+#include <bautils.h>
#include "backends/fs/symbian/symbian-fs-factory.h"
#include "backends/platform/symbian/src/SymbianOS.h"
#include "backends/platform/symbian/src/SymbianActions.h"
+#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
#include "common/events.h"
+#include "common/file.h"
#include "gui/Actions.h"
#include "gui/Key.h"
#include "gui/message.h"
@@ -42,14 +45,9 @@
#define SAMPLES_PER_SEC 16000
#endif
-#define KInputBufferLength 128
-// Symbian libc file functionality in order to provide shared file handles
-struct TSymbianFileEntry {
- RFile iFileHandle;
- char iInputBuffer[KInputBufferLength];
- TInt iInputBufferLen;
- TInt iInputPos;
-};
+
+#define DEFAULT_CONFIG_FILE "scummvm.ini"
+#define DEFAULT_SAVE_PATH "Savegames"
#define FILE void
@@ -118,8 +116,21 @@ void OSystem_SDL_Symbian::setFeatureState(Feature f, bool enable) {
}
}
-FilesystemFactory *OSystem_SDL_Symbian::getFilesystemFactory() {
- return &SymbianFilesystemFactory::instance();
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+ strcpy(configFile, Symbian::GetExecutablePath());
+ strcat(configFile, DEFAULT_CONFIG_FILE);
+ return configFile;
+}
+
+Common::SeekableReadStream *OSystem_SDL_Symbian::openConfigFileForReading() {
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForReading();
+}
+
+Common::WriteStream *OSystem_SDL_Symbian::openConfigFileForWriting() {
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForWriting();
}
OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = {
@@ -128,10 +139,33 @@ OSystem_SDL_Symbian::zoneDesc OSystem_SDL_Symbian::_zones[TOTAL_ZONES] = {
{ 150, 145, 170, 55 }
};
OSystem_SDL_Symbian::OSystem_SDL_Symbian() :_channels(0),_stereo_mix_buffer(0) {
+ _RFs = &CEikonEnv::Static()->FsSession();
+ _fsFactory = new SymbianFilesystemFactory();
}
void OSystem_SDL_Symbian::initBackend() {
+ // First set the extrapath (for installed dat files etc)
ConfMan.set("extrapath", Symbian::GetExecutablePath());
+
+ // Calculate the default savepath
+ Common::String savePath;
+ savePath = Symbian::GetExecutablePath();
+ savePath += DEFAULT_SAVE_PATH "\\";
+ _savefile = new DefaultSaveFileManager(savePath);
+
+ // If savepath has not already been set then set it
+ if (!ConfMan.hasKey("savepath")) {
+ ConfMan.set("savepath", savePath);
+
+ }
+
+ // Ensure that the current set path (might have been altered by the user) exists
+ Common::String currentPath = ConfMan.get("savepath");
+ TFileName fname;
+ TPtrC8 ptr((const unsigned char*)currentPath.c_str(),currentPath.size());
+ fname.Copy(ptr);
+ BaflUtils::EnsurePathExistsL(static_cast<OSystem_SDL_Symbian*>(g_system)->FsSession(), fname);
+
ConfMan.setBool("FM_high_quality", false);
#if !defined(S60) || defined(S60V3) // S60 has low quality as default
ConfMan.setBool("FM_medium_quality", true);
@@ -455,223 +489,60 @@ void OSystem_SDL_Symbian::initZones() {
}
}
-FILE* symbian_fopen(const char* name, const char* mode) {
- TSymbianFileEntry* fileEntry = new TSymbianFileEntry;
- fileEntry->iInputPos = KErrNotFound;
-
- if (fileEntry != NULL) {
- TInt modeLen = strlen(mode);
-
- TPtrC8 namePtr((unsigned char*) name, strlen(name));
- TFileName tempFileName;
- tempFileName.Copy(namePtr);
-
- TInt fileMode = EFileRead;
-
- if (mode[0] == 'a')
- fileMode = EFileWrite;
-
- if (!((modeLen > 1 && mode[1] == 'b') || (modeLen > 2 && mode[2] == 'b'))) {
- fileMode |= EFileStreamText;
- }
-
- if ((modeLen > 1 && mode[1] == '+') || (modeLen > 2 && mode[2] == '+')) {
- fileMode = fileMode| EFileWrite;
- }
-
- fileMode = fileMode| EFileShareAny;
-
- switch(mode[0]) {
- case 'a':
- if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) {
- if (fileEntry->iFileHandle.Create(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) {
- delete fileEntry;
- fileEntry = NULL;
- }
- }
- break;
- case 'r':
- if (fileEntry->iFileHandle.Open(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) {
- delete fileEntry;
- fileEntry = NULL;
- }
- break;
-
- case 'w':
- if (fileEntry->iFileHandle.Replace(CEikonEnv::Static()->FsSession(), tempFileName, fileMode) != KErrNone) {
- delete fileEntry;
- fileEntry = NULL;
- }
- break;
- }
- }
- return (FILE*) fileEntry;
-}
-
-void symbian_fclose(FILE* handle) {
- ((TSymbianFileEntry*)(handle))->iFileHandle.Close();
-
- delete (TSymbianFileEntry*)(handle);
+RFs& OSystem_SDL_Symbian::FsSession() {
+ return *_RFs;
}
-size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) {
- TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle));
- TUint32 totsize = size*numItems;
- TPtr8 pointer ( (unsigned char*) ptr, totsize);
-
- // Nothing cached and we want to load at least KInputBufferLength bytes
- if(totsize >= KInputBufferLength) {
- TUint32 totLength = 0;
- if(entry->iInputPos != KErrNotFound)
- {
- TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer+entry->iInputPos, entry->iInputBufferLen - entry->iInputPos, KInputBufferLength);
- pointer.Append(cacheBuffer);
- entry->iInputPos = KErrNotFound;
- totLength+=pointer.Length();
- pointer.Set(totLength+(unsigned char*) ptr, 0, totsize-totLength);
- }
-
- entry->iFileHandle.Read(pointer);
- totLength+=pointer.Length();
-
- pointer.Set((unsigned char*) ptr, totLength, totsize);
-
+// Symbian bsearch implementation is flawed
+void* scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
+ // Perform binary search
+ size_t lo = 0;
+ size_t hi = nmemb;
+ while (lo < hi) {
+ size_t mid = (lo + hi) / 2;
+ const void *p = ((const char *)base) + mid * size;
+ int tmp = (*compar)(key, p);
+ if (tmp < 0)
+ hi = mid;
+ else if (tmp > 0)
+ lo = mid + 1;
+ else
+ return (void *)p;
}
- else {
- // Nothing in buffer
- if(entry->iInputPos == KErrNotFound) {
- TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, KInputBufferLength);
- entry->iFileHandle.Read(cacheBuffer);
-
- if(cacheBuffer.Length() >= totsize) {
- pointer.Copy(cacheBuffer.Left(totsize));
- entry->iInputPos = totsize;
- entry->iInputBufferLen = cacheBuffer.Length();
- }
- else {
- pointer.Copy(cacheBuffer);
- entry->iInputPos = KErrNotFound;
- }
-
- }
- else {
- TPtr8 cacheBuffer( (unsigned char*) entry->iInputBuffer, entry->iInputBufferLen, KInputBufferLength);
- if(entry->iInputPos+totsize < entry->iInputBufferLen) {
- pointer.Copy(cacheBuffer.Mid(entry->iInputPos, totsize));
- entry->iInputPos+=totsize;
- }
- else {
-
- pointer.Copy(cacheBuffer.Mid(entry->iInputPos, entry->iInputBufferLen-entry->iInputPos));
- cacheBuffer.SetLength(0);
- entry->iFileHandle.Read(cacheBuffer);
-
- if(cacheBuffer.Length() >= totsize-pointer.Length()) {
- TUint32 restSize = totsize-pointer.Length();
- pointer.Append(cacheBuffer.Left(restSize));
- entry->iInputPos = restSize;
- entry->iInputBufferLen = cacheBuffer.Length();
- }
- else {
- pointer.Append(cacheBuffer);
- entry->iInputPos = KErrNotFound;
- }
- }
- }
- }
-
- return pointer.Length()/size;
-}
-
-size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
- TPtrC8 pointer( (unsigned char*) ptr, size*numItems);
-
- ((TSymbianFileEntry*)(handle))->iInputPos = KErrNotFound;
- if (((TSymbianFileEntry*)(handle))->iFileHandle.Write(pointer) == KErrNone) {
- return numItems;
- }
-
- return 0;
+ return NULL;
}
-bool symbian_feof(FILE* handle) {
- TInt pos = 0;
- TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle));
-
- if (entry->iFileHandle.Seek(ESeekCurrent, pos) == KErrNone) {
-
- TInt size = 0;
- if (entry->iFileHandle.Size(size) == KErrNone) {
- if(entry->iInputPos == KErrNotFound && pos == size)
- return true;
-
- if(entry->iInputPos != KErrNotFound && pos == size && entry->iInputPos == entry->iInputBufferLen)
- return true;
-
- return false;
- }
- }
- return true;
-}
-
-long int symbian_ftell(FILE* handle) {
- TInt pos = 0;
- TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle));
-
- entry->iFileHandle.Seek(ESeekCurrent, pos);
- if(entry->iInputPos != KErrNotFound)
- {
- pos+=(entry->iInputPos - entry->iInputBufferLen);
- }
- return pos;
-}
-
-int symbian_fseek(FILE* handle, long int offset, int whence) {
-
- TSeek seekMode = ESeekStart;
- TInt pos = offset;
- TSymbianFileEntry* entry = ((TSymbianFileEntry*)(handle));
-
- switch(whence) {
- case SEEK_SET:
- seekMode = ESeekStart;
- break;
- case SEEK_CUR:
- seekMode = ESeekCurrent;
- if(entry->iInputPos != KErrNotFound) {
- pos+=(entry->iInputPos - entry->iInputBufferLen);
- }
- break;
- case SEEK_END:
- seekMode = ESeekEnd;
- break;
-
- }
-
- entry->iInputPos = KErrNotFound;
-
- return entry->iFileHandle.Seek(seekMode, pos);
-}
-
-void symbian_clearerr(FILE* /*handle*/) {
+extern "C"
+{
+// Include the snprintf and vsnprintf implementations as 'C' code
+#include "vsnprintf.h"
}
/** Vibration support */
#ifdef USE_VIBRA_SE_PXXX
void OSystem_SDL_Symbian::initializeVibration() {
- _vibrationApi = SonyEricsson::CVibration::NewL();
+#ifdef UIQ3
+#else
+#endif
}
void OSystem_SDL_Symbian::vibrationOn(int vibraLength) {
- // initialize?
+#ifdef UIQ3
+ // initialize?
if (!_vibrationApi) _vibrationApi = SonyEricsson::CVibration::NewL();
// do it!
_vibrationApi->VibrationOn(1, 1, vibraLength);
+#else
+
+#endif
}
void OSystem_SDL_Symbian::vibrationOff() {
+#ifdef UIQ3
+#else
_vibrationApi->VibrationOff();
+#endif
}
#endif // USE_SE_PXX_VIBRA
diff --git a/backends/platform/symbian/src/SymbianOS.h b/backends/platform/symbian/src/SymbianOS.h
index 71d24f6286..03d7fb972c 100644
--- a/backends/platform/symbian/src/SymbianOS.h
+++ b/backends/platform/symbian/src/SymbianOS.h
@@ -27,12 +27,8 @@
#include "backends/platform/sdl/sdl.h"
-/** Vibration support */
-#ifdef USE_VIBRA_SE_PXXX
-#include <vibration.h>
-#endif
-
#define TOTAL_ZONES 3
+class RFs;
class OSystem_SDL_Symbian : public OSystem_SDL {
public:
@@ -62,6 +58,9 @@ public:
// Overloaded from SDL_Commmon
void quit();
+
+ // Returns reference to File session
+ RFs& FsSession();
protected:
//
// The mixer callback function, passed on to OSystem::setSoundCallback().
@@ -70,7 +69,9 @@ protected:
//
static void symbianMixCallback(void *s, byte *samples, int len);
- virtual FilesystemFactory *getFilesystemFactory();
+
+ virtual Common::SeekableReadStream *openConfigFileForReading();
+ virtual Common::WriteStream *openConfigFileForWriting();
public:
// vibration support
#ifdef USE_VIBRA_SE_PXXX
@@ -131,6 +132,7 @@ protected:
} zoneDesc;
static zoneDesc _zones[TOTAL_ZONES];
+ RFs* _RFs;
};
#endif
diff --git a/backends/platform/symbian/src/main_features.inl b/backends/platform/symbian/src/main_features.inl
deleted file mode 100644
index f572ddb3dd..0000000000
--- a/backends/platform/symbian/src/main_features.inl
+++ /dev/null
@@ -1,93 +0,0 @@
-/* ScummVM - Scumm Interpreter
- * Copyright (C) 2003-2005 Andreas 'Sprawl' Karlsson - Original EPOC port, ESDL
- * Copyright (C) 2003-2005 Lars 'AnotherGuest' Persson - Original EPOC port, Audio System
- * Copyright (C) 2005 Jurgen 'SumthinWicked' Braam - EPOC/CVS maintainer
- * Copyright (C) 2005-2006 The ScummVM project
- *
- * 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.
- *
- */
-
-#ifdef USE_VIBRA_SE_PXXX
- "Vibra "
-#endif
- "\n"
-
-// we want a list of supported engines visible in the program,
-// because we also release special builds with only one engine
-#ifndef DISABLE_SCUMM
- "SCUMM "
-#endif
-#ifndef DISABLE_AGOS
- "AGOS "
-#endif
-#ifndef DISABLE_SKY
- "Sky "
-#endif
-#ifndef DISABLE_QUEEN
- "Queen "
-#endif
-#ifndef DISABLE_GOB
- "Gob "
-#endif
-#ifndef DISABLE_SAGA
- "Saga "
-#endif
-#ifndef DISABLE_KYRA
- "Kyra "
-#endif
-#ifndef DISABLE_SWORD1
- "Sword1 "
-#endif
-#ifndef DISABLE_SWORD2
- "Sword2 "
-#endif
-#ifndef DISABLE_CINE
- "Cine "
-#endif
-#ifndef DISABLE_LURE
- "Lure "
-#endif
-#ifndef DISABLE_AGI
- "AGI "
-#endif
-#ifndef DISABLE_TOUCHE
- "Touche "
-#endif
-#ifndef DISABLE_DRASCULA
- "Drascula "
-#endif
-#ifndef DISABLE_IGOR
- "Igor "
-#endif
-#ifndef DISABLE_PARALLACTION
- "Parallaction "
-#endif
-#ifndef DISABLE_CRUISE
- "Cruise "
-#endif
-#ifndef DISABLE_MADE
- "MADE "
-#endif
-
-#ifndef DISABLE_M4
- "M4 "
-#endif
-
-
-
-
-
-
diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h
index 06a4cf374c..ab8333c986 100644
--- a/backends/platform/symbian/src/portdefs.h
+++ b/backends/platform/symbian/src/portdefs.h
@@ -35,9 +35,6 @@
#include <e32std.h>
#include <math.h>
-//#define DISABLE_SCALERS // we only need 1x
-//#define DISABLE_HQ_SCALERS
-
#if defined(USE_TREMOR) && !defined(USE_VORBIS)
#define USE_VORBIS // make sure this one is defined together with USE_TREMOR!
#endif
@@ -107,51 +104,31 @@
*/
#elif defined (__WINS__) // WINS
+ extern "C" int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...);
+ extern "C" int symbian_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap);
+ #define snprintf(buf,len,args...) symbian_snprintf(buf,len,args)
+ #define vsnprintf(buf,len,format,valist) symbian_vsnprintf(buf,len,format,valist)
- // let's just blatantly ignore this for now and just get it to work :P but does n't work from the debug function
- int inline scumm_snprintf (char *str, unsigned long /*n*/, char const *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vsprintf(str, fmt, args);
- va_end(args);
- return strlen(str);
- }
-
- int inline scumm_vsnprintf (char *str, unsigned long /*n*/, char const *fmt, va_list valist) {
- vsprintf(str, fmt, valist);
- return strlen(str);
- }
-
- #define snprintf scumm_snprintf
- #define vsnprintf scumm_vsnprintf
void* symbian_malloc (size_t _size);
#define malloc symbian_malloc
#else // GCCE and the rest
- #define snprintf(buf,len,args...) sprintf(buf,args)
- #define vsnprintf(buf,len,format,valist) vsprintf(buf,format,valist)
+ extern "C" int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...);
+ extern "C" int symbian_vsnprintf(char *text, size_t maxlen, const char *fmt, va_list ap);
+ #define snprintf(buf,len,args...) symbian_snprintf(buf,len,args)
+ #define vsnprintf(buf,len,format,valist) symbian_vsnprintf(buf,len,format,valist)
#endif
#ifndef __WINS__
#define USE_ARM_GFX_ASM
-#define ARM_USE_GFX_ASM
#define USE_ARM_SMUSH_ASM
#define USE_ARM_COSTUME_ASM
#define USE_ARM_SOUND_ASM
#endif
-// somehow nobody has this function...
-#define hypot(a, b) sqrt((a)*(a) + (b)*(b))
// Symbian bsearch implementation is flawed
-void inline *scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
- size_t i;
-
- for (i=0; i < nmemb; i++)
- if (compar(key, (void *)((size_t)base + size * i)) == 0)
- return (void *)((size_t)base + size * i);
- return NULL;
-}
-#define bsearch scumm_bsearch
+void *scumm_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
+#define bsearch scumm_bsearch
// we cannot include SymbianOS.h everywhere, but this works too (functions code is in SymbianOS.cpp)
namespace Symbian {
diff --git a/backends/platform/symbian/src/vsnprintf.h b/backends/platform/symbian/src/vsnprintf.h
new file mode 100644
index 0000000000..5ed04b1980
--- /dev/null
+++ b/backends/platform/symbian/src/vsnprintf.h
@@ -0,0 +1,668 @@
+/*
+ * This is the vsnprintf for scummvm/symbian implementation from the original snprintf.c,
+ * all support functions has been removed and vsnprintf renamed to symbian_vsnprintf
+ * snprintf.c - a portable implementation of snprintf
+ * According to the homepage this function could be licensed as either Frontier Aritistic or GPL.
+ *
+ * AUTHOR
+ * Mark Martinec <mark.martinec@ijs.si>, April 1999.
+ *
+ * Copyright 1999, Mark Martinec. All rights reserved.
+ *
+ * TERMS AND CONDITIONS
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the "Frontier Artistic License" which comes
+ * with this Kit.
+ *
+ * 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 Frontier Artistic License for more details.
+ *
+ * You should have received a copy of the Frontier Artistic License
+ * with this Kit in the file named LICENSE.txt .
+ * If not, I'll be glad to provide one.
+ *
+ * FEATURES
+ * - careful adherence to specs regarding flags, field width and precision;
+ * - good performance for large string handling (large format, large
+ * argument or large paddings). Performance is similar to system's sprintf
+ * and in several cases significantly better (make sure you compile with
+ * optimizations turned on, tell the compiler the code is strict ANSI
+ * if necessary to give it more freedom for optimizations);
+ * - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
+ * - written in standard ISO/ANSI C - requires an ANSI C compiler.
+ *
+ * SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
+ *
+ * This snprintf only supports the following conversion specifiers:
+ * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
+ * with flags: '-', '+', ' ', '0' and '#'.
+ * An asterisk is supported for field width as well as precision.
+ *
+ * Length modifiers 'h' (short int), 'l' (long int),
+ * and 'll' (long long int) are supported.
+ * NOTE:
+ * If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the
+ * length modifier 'll' is recognized but treated the same as 'l',
+ * which may cause argument value truncation! Defining
+ * SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also
+ * handles length modifier 'll'. long long int is a language extension
+ * which may not be portable.
+ *
+ * Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
+ * with length modifiers (none or h, l, ll) is left to the system routine
+ * sprintf, but all handling of flags, field width and precision as well as
+ * c and s conversions is done very carefully by this portable routine.
+ * If a string precision (truncation) is specified (e.g. %.8s) it is
+ * guaranteed the string beyond the specified precision will not be referenced.
+ *
+ * Length modifiers h, l and ll are ignored for c and s conversions (data
+ * types wint_t and wchar_t are not supported).
+ *
+ * The following common synonyms for conversion characters are supported:
+ * - i is a synonym for d
+ * - D is a synonym for ld, explicit length modifiers are ignored
+ * - U is a synonym for lu, explicit length modifiers are ignored
+ * - O is a synonym for lo, explicit length modifiers are ignored
+ * The D, O and U conversion characters are nonstandard, they are supported
+ * for backward compatibility only, and should not be used for new code.
+ *
+ * The following is specifically NOT supported:
+ * - flag ' (thousands' grouping character) is recognized but ignored
+ * - numeric conversion specifiers: f, e, E, g, G and synonym F,
+ * as well as the new a and A conversion specifiers
+ * - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
+ * - wide character/string conversions: lc, ls, and nonstandard
+ * synonyms C and S
+ * - writeback of converted string length: conversion character n
+ * - the n$ specification for direct reference to n-th argument
+ * - locales
+ *
+ * It is permitted for str_m to be zero, and it is permitted to specify NULL
+ * pointer for resulting string argument if str_m is zero (as per ISO C99).
+ *
+ * The return value is the number of characters which would be generated
+ * for the given input, excluding the trailing null. If this value
+ * is greater or equal to str_m, not all characters from the result
+ * have been stored in str, output bytes beyond the (str_m-1) -th character
+ * are discarded. If str_m is greater than zero it is guaranteed
+ * the resulting string will be null-terminated.
+ *
+ * NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
+ * but is different from some older and vendor implementations,
+ * and is also different from XPG, XSH5, SUSv2 specifications.
+ * For historical discussion on changes in the semantics and standards
+ * of snprintf see printf(3) man page in the Linux programmers manual.
+ *
+ * Routines asprintf and vasprintf return a pointer (in the ptr argument)
+ * to a buffer sufficiently large to hold the resulting string. This pointer
+ * should be passed to free(3) to release the allocated storage when it is
+ * no longer needed. If sufficient space cannot be allocated, these functions
+ * will return -1 and set ptr to be a NULL pointer. These two routines are a
+ * GNU C library extensions (glibc).
+ *
+ * Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
+ * yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
+ * characters into the allocated output string, the last character in the
+ * allocated buffer then gets the terminating null. If the formatted string
+ * length (the return value) is greater than or equal to the str_m argument,
+ * the resulting string was truncated and some of the formatted characters
+ * were discarded. These routines present a handy way to limit the amount
+ * of allocated memory to some sane value.
+ *
+ * AVAILABILITY
+ * http://www.ijs.si/software/snprintf/
+ *
+ * REVISION HISTORY
+ * 1999-04 V0.9 Mark Martinec
+ * - initial version, some modifications after comparing printf
+ * man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10,
+ * and checking how Perl handles sprintf (differently!);
+ * 1999-04-09 V1.0 Mark Martinec <mark.martinec@ijs.si>
+ * - added main test program, fixed remaining inconsistencies,
+ * added optional (long long int) support;
+ * 1999-04-12 V1.1 Mark Martinec <mark.martinec@ijs.si>
+ * - support the 'p' conversion (pointer to void);
+ * - if a string precision is specified
+ * make sure the string beyond the specified precision
+ * will not be referenced (e.g. by strlen);
+ * 1999-04-13 V1.2 Mark Martinec <mark.martinec@ijs.si>
+ * - support synonyms %D=%ld, %U=%lu, %O=%lo;
+ * - speed up the case of long format string with few conversions;
+ * 1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si>
+ * - fixed runaway loop (eventually crashing when str_l wraps
+ * beyond 2^31) while copying format string without
+ * conversion specifiers to a buffer that is too short
+ * (thanks to Edwin Young <edwiny@autonomy.com> for
+ * spotting the problem);
+ * - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR)
+ * to snprintf.h
+ * 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si>
+ * - relaxed license terms: The Artistic License now applies.
+ * You may still apply the GNU GENERAL PUBLIC LICENSE
+ * as was distributed with previous versions, if you prefer;
+ * - changed REVISION HISTORY dates to use ISO 8601 date format;
+ * - added vsnprintf (patch also independently proposed by
+ * Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
+ * 2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si>
+ * - removed POSIX check for str_m<1; value 0 for str_m is
+ * allowed by ISO C99 (and GNU C library 2.1) - (pointed out
+ * on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie).
+ * Besides relaxed license this change in standards adherence
+ * is the main reason to bump up the major version number;
+ * - added nonstandard routines asnprintf, vasnprintf, asprintf,
+ * vasprintf that dynamically allocate storage for the
+ * resulting string; these routines are not compiled by default,
+ * see comments where NEED_V?ASN?PRINTF macros are defined;
+ * - autoconf contributed by Caolan McNamara
+ * 2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si>
+ * - BUG FIX: the %c conversion used a temporary variable
+ * that was no longer in scope when referenced,
+ * possibly causing incorrect resulting character;
+ * - BUG FIX: make precision and minimal field width unsigned
+ * to handle huge values (2^31 <= n < 2^32) correctly;
+ * also be more careful in the use of signed/unsigned/size_t
+ * internal variables - probably more careful than many
+ * vendor implementations, but there may still be a case
+ * where huge values of str_m, precision or minimal field
+ * could cause incorrect behaviour;
+ * - use separate variables for signed/unsigned arguments,
+ * and for short/int, long, and long long argument lengths
+ * to avoid possible incompatibilities on certain
+ * computer architectures. Also use separate variable
+ * arg_sign to hold sign of a numeric argument,
+ * to make code more transparent;
+ * - some fiddling with zero padding and "0x" to make it
+ * Linux compatible;
+ * - systematically use macros fast_memcpy and fast_memset
+ * instead of case-by-case hand optimization; determine some
+ * breakeven string lengths for different architectures;
+ * - terminology change: 'format' -> 'conversion specifier',
+ * 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")',
+ * 'alternative form' -> 'alternate form',
+ * 'data type modifier' -> 'length modifier';
+ * - several comments rephrased and new ones added;
+ * - make compiler not complain about 'credits' defined but
+ * not used;
+ */
+/* ============================================= */
+/* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */
+/* ============================================= */
+
+#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
+#define PORTABLE_SNPRINTF_VERSION_MINOR 2
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <errno.h>
+#ifdef isdigit
+#undef isdigit
+#endif
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+
+#ifndef breakeven_point
+# define breakeven_point 6 /* some reasonable one-size-fits-all value */
+#endif
+
+#define fast_memcpy(d,s,n) \
+{ register size_t nn = (size_t)(n); \
+ if (nn >= breakeven_point) memcpy((d), (s), nn); \
+ else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
+ register char *dd; register const char *ss; \
+for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
+
+#define fast_memset(d,c,n) \
+{ register size_t nn = (size_t)(n); \
+ if (nn >= breakeven_point) memset((d), (int)(c), nn); \
+ else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
+ register char *dd; register const int cc=(int)(c); \
+for (dd=(d); nn>0; nn--) *dd++ = cc; } }
+
+
+/* declarations */
+
+static char credits[] = "\n\
+@(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
+@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
+@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
+int symbian_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
+
+ size_t str_l = 0;
+ const char *p = fmt;
+
+ /* In contrast with POSIX, the ISO C99 now says
+ * that str can be NULL and str_m can be 0.
+ * This is more useful than the old: if (str_m < 1) return -1; */
+
+ if (!p) p = "";
+ while (*p) {
+ if (*p != '%') {
+ /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
+ /* but the following code achieves better performance for cases
+ * where format string is long and contains few conversions */
+ const char *q = strchr(p+1,'%');
+ size_t n = !q ? strlen(p) : (q-p);
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memcpy(str+str_l, p, (n>avail?avail:n));
+ }
+ p += n; str_l += n;
+ } else {
+ const char *starting_p;
+ size_t min_field_width = 0, precision = 0;
+ int zero_padding = 0, precision_specified = 0, justify_left = 0;
+ int alternate_form = 0, force_sign = 0;
+ int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
+ the ' ' flag should be ignored. */
+ char length_modifier = '\0'; /* allowed values: \0, h, l, L */
+ char tmp[32];/* temporary buffer for simple numeric->string conversion */
+
+ const char *str_arg; /* string address in case of string argument */
+ size_t str_arg_l; /* natural field width of arg without padding
+ and sign */
+ unsigned char uchar_arg;
+ /* unsigned char argument value - only defined for c conversion.
+ N.B. standard explicitly states the char argument for
+ the c conversion is unsigned */
+
+ size_t number_of_zeros_to_pad = 0;
+ /* number of zeros to be inserted for numeric conversions
+ as required by the precision or minimal field width */
+
+ size_t zero_padding_insertion_ind = 0;
+ /* index into tmp where zero padding is to be inserted */
+
+ char fmt_spec = '\0';
+ /* current conversion specifier character */
+
+ str_arg = credits;/* just to make compiler happy (defined but not used)*/
+ str_arg = NULL;
+ starting_p = p; p++; /* skip '%' */
+ /* parse flags */
+ while (*p == '0' || *p == '-' || *p == '+' ||
+ *p == ' ' || *p == '#' || *p == '\'') {
+ switch (*p) {
+ case '0': zero_padding = 1; break;
+ case '-': justify_left = 1; break;
+ case '+': force_sign = 1; space_for_positive = 0; break;
+ case ' ': force_sign = 1;
+ /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
+ break;
+ case '#': alternate_form = 1; break;
+ case '\'': break;
+ }
+ p++;
+ }
+ /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
+
+ /* parse field width */
+ if (*p == '*') {
+ int j;
+ p++; j = va_arg(ap, int);
+ if (j >= 0) min_field_width = j;
+ else { min_field_width = -j; justify_left = 1; }
+ } else if (isdigit((int)(*p))) {
+ /* size_t could be wider than unsigned int;
+ make sure we treat argument like common implementations do */
+ unsigned int uj = *p++ - '0';
+ while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
+ min_field_width = uj;
+ }
+ /* parse precision */
+ if (*p == '.') {
+ p++; precision_specified = 1;
+ if (*p == '*') {
+ int j = va_arg(ap, int);
+ p++;
+ if (j >= 0) precision = j;
+ else {
+ precision_specified = 0; precision = 0;
+ /* NOTE:
+ * Solaris 2.6 man page claims that in this case the precision
+ * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
+ * claim that this case should be treated as unspecified precision,
+ * which is what we do here.
+ */
+ }
+ } else if (isdigit((int)(*p))) {
+ /* size_t could be wider than unsigned int;
+ make sure we treat argument like common implementations do */
+ unsigned int uj = *p++ - '0';
+ while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
+ precision = uj;
+ }
+ }
+ /* parse 'h', 'l' and 'll' length modifiers */
+ if (*p == 'h' || *p == 'l') {
+ length_modifier = *p; p++;
+ if (length_modifier == 'l' && *p == 'l') { /* double l = long long */
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ length_modifier = '2'; /* double l encoded as '2' */
+#else
+ length_modifier = 'l'; /* treat it as a single 'l' */
+#endif
+ p++;
+ }
+ }
+ fmt_spec = *p;
+ /* common synonyms: */
+ switch (fmt_spec) {
+ case 'i': fmt_spec = 'd'; break;
+ case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
+ case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
+ case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
+ default: break;
+ }
+ /* get parameter value, do initial processing */
+ switch (fmt_spec) {
+ case '%': /* % behaves similar to 's' regarding flags and field widths */
+ case 'c': /* c behaves similar to 's' regarding flags and field widths */
+ case 's':
+ length_modifier = '\0'; /* wint_t and wchar_t not supported */
+ /* the result of zero padding flag with non-numeric conversion specifier*/
+ /* is undefined. Solaris and HPUX 10 does zero padding in this case, */
+ /* Digital Unix and Linux does not. */
+ zero_padding = 0; /* turn zero padding off for string conversions */
+ str_arg_l = 1;
+ switch (fmt_spec) {
+ case '%':
+ str_arg = p; break;
+ case 'c': {
+ int j = va_arg(ap, int);
+ uchar_arg = (unsigned char) j; /* standard demands unsigned char */
+ str_arg = (const char *) &uchar_arg;
+ break;
+ }
+ case 's':
+ str_arg = va_arg(ap, const char *);
+ if (!str_arg) str_arg_l = 0;
+ /* make sure not to address string beyond the specified precision !!! */
+ else if (!precision_specified) str_arg_l = strlen(str_arg);
+ /* truncate string if necessary as requested by precision */
+ else if (precision == 0) str_arg_l = 0;
+ else {
+ /* memchr on HP does not like n > 2^31 !!! */
+ const char *q = (const char*) memchr(str_arg, '\0',
+ precision <= 0x7fffffff ? precision : 0x7fffffff);
+ str_arg_l = !q ? precision : (q-str_arg);
+ }
+ break;
+ default: break;
+ }
+ break;
+ case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
+ /* NOTE: the u, o, x, X and p conversion specifiers imply
+ the value is unsigned; d implies a signed value */
+
+ int arg_sign = 0;
+ /* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
+ +1 if greater than zero (or nonzero for unsigned arguments),
+ -1 if negative (unsigned argument is never negative) */
+
+ int int_arg = 0; unsigned int uint_arg = 0;
+ /* only defined for length modifier h, or for no length modifiers */
+
+ long int long_arg = 0; unsigned long int ulong_arg = 0;
+ /* only defined for length modifier l */
+
+ void *ptr_arg = NULL;
+ /* pointer argument value -only defined for p conversion */
+
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ long long int long_long_arg = 0;
+ unsigned long long int ulong_long_arg = 0;
+ /* only defined for length modifier ll */
+#endif
+ if (fmt_spec == 'p') {
+ /* HPUX 10: An l, h, ll or L before any other conversion character
+ * (other than d, i, u, o, x, or X) is ignored.
+ * Digital Unix:
+ * not specified, but seems to behave as HPUX does.
+ * Solaris: If an h, l, or L appears before any other conversion
+ * specifier (other than d, i, u, o, x, or X), the behavior
+ * is undefined. (Actually %hp converts only 16-bits of address
+ * and %llp treats address as 64-bit data which is incompatible
+ * with (void *) argument on a 32-bit system).
+ */
+ length_modifier = '\0';
+ ptr_arg = va_arg(ap, void *);
+ if (ptr_arg != NULL) arg_sign = 1;
+ } else if (fmt_spec == 'd') { /* signed */
+ switch (length_modifier) {
+ case '\0':
+ case 'h':
+ /* It is non-portable to specify a second argument of char or short
+ * to va_arg, because arguments seen by the called function
+ * are not char or short. C converts char and short arguments
+ * to int before passing them to a function.
+ */
+ int_arg = va_arg(ap, int);
+ if (int_arg > 0) arg_sign = 1;
+ else if (int_arg < 0) arg_sign = -1;
+ break;
+ case 'l':
+ long_arg = va_arg(ap, long int);
+ if (long_arg > 0) arg_sign = 1;
+ else if (long_arg < 0) arg_sign = -1;
+ break;
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ case '2':
+ long_long_arg = va_arg(ap, long long int);
+ if (long_long_arg > 0) arg_sign = 1;
+ else if (long_long_arg < 0) arg_sign = -1;
+ break;
+#endif
+ }
+ } else { /* unsigned */
+ switch (length_modifier) {
+ case '\0':
+ case 'h':
+ uint_arg = va_arg(ap, unsigned int);
+ if (uint_arg) arg_sign = 1;
+ break;
+ case 'l':
+ ulong_arg = va_arg(ap, unsigned long int);
+ if (ulong_arg) arg_sign = 1;
+ break;
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ case '2':
+ ulong_long_arg = va_arg(ap, unsigned long long int);
+ if (ulong_long_arg) arg_sign = 1;
+ break;
+#endif
+ }
+ }
+ str_arg = tmp; str_arg_l = 0;
+ /* NOTE:
+ * For d, i, u, o, x, and X conversions, if precision is specified,
+ * the '0' flag should be ignored. This is so with Solaris 2.6,
+ * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
+ */
+ if (precision_specified) zero_padding = 0;
+ if (fmt_spec == 'd') {
+ if (force_sign && arg_sign >= 0)
+ tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
+ /* leave negative numbers for sprintf to handle,
+ to avoid handling tricky cases like (short int)(-32768) */
+ } else if (alternate_form) {
+ if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
+ { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
+ /* alternate form should have no effect for p conversion, but ... */
+ }
+ zero_padding_insertion_ind = str_arg_l;
+ if (!precision_specified) precision = 1; /* default precision is 1 */
+ if (precision == 0 && arg_sign == 0
+ ) {
+ /* converted to null string */
+ /* When zero value is formatted with an explicit precision 0,
+ the resulting formatted string is empty (d, i, u, o, x, X, p). */
+ } else {
+ char f[5]; int f_l = 0;
+ f[f_l++] = '%'; /* construct a simple format string for sprintf */
+ if (!length_modifier) { }
+ else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
+ else f[f_l++] = length_modifier;
+ f[f_l++] = fmt_spec; f[f_l++] = '\0';
+ if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
+ else if (fmt_spec == 'd') { /* signed */
+ switch (length_modifier) {
+ case '\0':
+ case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
+ case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
+#endif
+ }
+ } else { /* unsigned */
+ switch (length_modifier) {
+ case '\0':
+ case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
+ case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
+#ifdef SNPRINTF_LONGLONG_SUPPORT
+ case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
+#endif
+ }
+ }
+ /* include the optional minus sign and possible "0x"
+ in the region before the zero padding insertion point */
+ if (zero_padding_insertion_ind < str_arg_l &&
+ tmp[zero_padding_insertion_ind] == '-') {
+ zero_padding_insertion_ind++;
+ }
+ if (zero_padding_insertion_ind+1 < str_arg_l &&
+ tmp[zero_padding_insertion_ind] == '0' &&
+ (tmp[zero_padding_insertion_ind+1] == 'x' ||
+ tmp[zero_padding_insertion_ind+1] == 'X') ) {
+ zero_padding_insertion_ind += 2;
+ }
+ }
+ { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
+ if (alternate_form && fmt_spec == 'o'
+ /* unless zero is already the first character */
+ && !(zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0')
+ ) { /* assure leading zero for alternate-form octal numbers */
+ if (!precision_specified || precision < num_of_digits+1) {
+ /* precision is increased to force the first character to be zero,
+ except if a zero value is formatted with an explicit precision
+ of zero */
+ precision = num_of_digits+1; precision_specified = 1;
+ }
+ }
+ /* zero padding to specified precision? */
+ if (num_of_digits < precision)
+ number_of_zeros_to_pad = precision - num_of_digits;
+ }
+ /* zero padding to specified minimal field width? */
+ if (!justify_left && zero_padding) {
+ int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ if (n > 0) number_of_zeros_to_pad += n;
+ }
+ break;
+ }
+ default: /* unrecognized conversion specifier, keep format string as-is*/
+ zero_padding = 0; /* turn zero padding off for non-numeric convers. */
+ justify_left = 1; min_field_width = 0; /* reset flags */
+ /* discard the unrecognized conversion, just keep *
+ * the unrecognized conversion character */
+ str_arg = p; str_arg_l = 0;
+ if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
+ if not at end-of-string */
+ break;
+ }
+ if (*p) p++; /* step over the just processed conversion specifier */
+ /* insert padding to the left as requested by min_field_width;
+ this does not include the zero padding in case of numerical conversions*/
+ if (!justify_left) { /* left padding with blank or zero */
+ int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ if (n > 0) {
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
+ }
+ str_l += n;
+ }
+ }
+ /* zero padding as requested by the precision or by the minimal field width
+ * for numeric conversions required? */
+ if (number_of_zeros_to_pad <= 0) {
+ /* will not copy first part of numeric right now, *
+ * force it to be copied later in its entirety */
+ zero_padding_insertion_ind = 0;
+ } else {
+ /* insert first part of numerics (sign or '0x') before zero padding */
+ int n = zero_padding_insertion_ind;
+ if (n > 0) {
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
+ }
+ str_l += n;
+ }
+ /* insert zero padding as requested by the precision or min field width */
+ n = number_of_zeros_to_pad;
+ if (n > 0) {
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memset(str+str_l, '0', (n>avail?avail:n));
+ }
+ str_l += n;
+ }
+ }
+ /* insert formatted string
+ * (or as-is conversion specifier for unknown conversions) */
+ { int n = str_arg_l - zero_padding_insertion_ind;
+ if (n > 0) {
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
+ (n>avail?avail:n));
+ }
+ str_l += n;
+ }
+ }
+ /* insert right padding */
+ if (justify_left) { /* right blank padding to the field width */
+ int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
+ if (n > 0) {
+ if (str_l < str_m) {
+ size_t avail = str_m-str_l;
+ fast_memset(str+str_l, ' ', (n>avail?avail:n));
+ }
+ str_l += n;
+ }
+ }
+ }
+ }
+ if (str_m > 0) { /* make sure the string is null-terminated
+ even at the expense of overwriting the last character
+ (shouldn't happen, but just in case) */
+ str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
+ }
+ /* Return the number of characters formatted (excluding trailing null
+ * character), that is, the number of characters that would have been
+ * written to the buffer if it were large enough.
+ *
+ * The value of str_l should be returned, but str_l is of unsigned type
+ * size_t, and snprintf is int, possibly leading to an undetected
+ * integer overflow, resulting in a negative return value, which is illegal.
+ * Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
+ * Should errno be set to EOVERFLOW and EOF returned in this case???
+ */
+ return (int) str_l;
+}
+
+int symbian_snprintf(char *text, size_t maxlen, const char *fmt, ...) {
+ va_list ap;
+ int retval;
+
+ va_start(ap, fmt);
+ retval = symbian_vsnprintf(text, maxlen, fmt, ap);
+ va_end(ap);
+
+ return retval;
+}
diff --git a/backends/platform/wii/Makefile b/backends/platform/wii/Makefile
index a52ceb1774..90ebcccb66 100644
--- a/backends/platform/wii/Makefile
+++ b/backends/platform/wii/Makefile
@@ -1,26 +1,32 @@
+# this enables port specific debug messages and redirects stdout/err over
+# usbgecko in memcard slot b
DEBUG_WII = 1
-ENABLE_SCUMM = 1
-ENABLE_SCUMM_7_8 = 1
-ENABLE_HE = 1
-# ENABLE_AGI = 1
-ENABLE_AGOS = 1
-ENABLE_CINE = 1
-ENABLE_CRUISE = 1
-ENABLE_DRASCULA = 1
-ENABLE_GOB = 1
-ENABLE_IGOR = 1
-ENABLE_KYRA = 1
-ENABLE_LURE = 1
-ENABLE_M4 = 1
-ENABLE_MADE = 1
-ENABLE_PARALLACTION = 1
-ENABLE_QUEEN = 1
-ENABLE_SAGA = 1
-ENABLE_SKY = 1
-ENABLE_SWORD1 = 1
-ENABLE_SWORD2 = 1
-ENABLE_TOUCHE = 1
+# builds a gamecube version. cleanup object files before flipping this
+GAMECUBE = 0
+
+ENABLE_SCUMM = STATIC_PLUGIN
+ENABLE_SCUMM_7_8 = STATIC_PLUGIN
+ENABLE_HE = STATIC_PLUGIN
+# ENABLE_AGI = STATIC_PLUGIN
+ENABLE_AGOS = STATIC_PLUGIN
+ENABLE_CINE = STATIC_PLUGIN
+ENABLE_CRUISE = STATIC_PLUGIN
+ENABLE_DRASCULA = STATIC_PLUGIN
+ENABLE_GOB = STATIC_PLUGIN
+ENABLE_IGOR = STATIC_PLUGIN
+ENABLE_KYRA = STATIC_PLUGIN
+ENABLE_LURE = STATIC_PLUGIN
+ENABLE_M4 = STATIC_PLUGIN
+ENABLE_MADE = STATIC_PLUGIN
+ENABLE_PARALLACTION = STATIC_PLUGIN
+ENABLE_QUEEN = STATIC_PLUGIN
+ENABLE_SAGA = STATIC_PLUGIN
+ENABLE_SKY = STATIC_PLUGIN
+ENABLE_SWORD1 = STATIC_PLUGIN
+ENABLE_SWORD2 = STATIC_PLUGIN
+ENABLE_TINSEL = STATIC_PLUGIN
+ENABLE_TOUCHE = STATIC_PLUGIN
DISABLE_HQ_SCALERS = 1
DISABLE_SCALERS = 1
@@ -30,7 +36,11 @@ USE_MAD = 1
USE_TREMOR = 1
USE_FLAC = 1
USE_MPEG2 = 1
+ifeq ($(GAMECUBE),1)
+USE_MT32EMU = 0
+else
USE_MT32EMU = 1
+endif
srcdir = ../../..
VPATH = $(srcdir)
@@ -54,21 +64,28 @@ MKDIR = mkdir -p
RM = rm -f
CP = cp -f
+ifeq ($(GAMECUBE),1)
+TARGET = scummvm-gc
+MACHDEP = -DGEKKO -DGAMECUBE -mogc -mcpu=750 -meabi -mhard-float \
+ -ffunction-sections -fdata-sections -fmodulo-sched
+LIBDIR = $(DEVKITPRO)/libogc/lib/cube
+LIBS = -lstdc++ -lfat -logc -lm
+else
TARGET = scummvm-wii
-
MACHDEP = -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float \
-ffunction-sections -fdata-sections -fmodulo-sched
+LIBDIR = $(DEVKITPRO)/libogc/lib/wii
+LIBS = -lstdc++ -lfat -lwiiuse -lbte -logc -lm
+endif
INCDIR = $(srcdir) . $(srcdir)/engines/ $(DEVKITPRO)/libogc/include
-LIBDIR = $(DEVKITPRO)/libogc/lib/wii
CXXFLAGS = -g -Os -Wall $(MACHDEP) -D__WII__ -Wno-multichar -Wno-long-long \
- -Wno-unknown-pragmas -Wno-reorder -fno-exceptions -fno-rtti
+ -Wno-unknown-pragmas -Wno-reorder -fno-exceptions -fno-rtti
CXXFLAGS += $(addprefix -I,$(INCDIR))
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(TARGET).elf.map
LDFLAGS += $(addprefix -L,$(LIBDIR))
-LIBS = -lstdc++ -lfat -lwiiuse -lbte -logc -lm
CXXFLAGS += -I$(DEVKITPRO)/3rd/wii/include
LDFLAGS += -L$(DEVKITPRO)/3rd/wii/lib
@@ -138,19 +155,27 @@ distclean-wii:
@-$(RM) dist
upload:
+ifeq ($(GAMECUBE),1)
+ $(DEVKITPPC)/bin/geckoupload $(TARGET).dol
+else
$(DEVKITPPC)/bin/wiiload $(TARGET).dol
+endif
dist:
- $(MKDIR) dist/apps/scummvm
- $(CP) $(TARGET).dol dist/apps/scummvm/boot.dol
- $(CP) $(DISTPATH)/meta.xml dist/apps/scummvm/
- $(CP) $(DISTPATH)/icon.png dist/apps/scummvm/
- $(CP) $(DISTPATH)/READMII dist/apps/scummvm/
- $(CP) $(srcdir)/AUTHORS dist/apps/scummvm/
- $(CP) $(srcdir)/COPYING dist/apps/scummvm/
- $(CP) $(srcdir)/COPYRIGHT dist/apps/scummvm/
- $(CP) $(srcdir)/NEWS dist/apps/scummvm/
- $(CP) $(srcdir)/README dist/apps/scummvm/
- $(CP) $(DIST_FILES_THEMES) dist/apps/scummvm/
- $(CP) $(DIST_FILES_ENGINEDATA) dist/apps/scummvm/
+ $(MKDIR) dist/scummvm
+ifeq ($(GAMECUBE),1)
+ $(CP) $(TARGET).dol dist/scummvm/
+else
+ $(CP) $(TARGET).dol dist/scummvm/boot.dol
+ $(CP) $(DISTPATH)/meta.xml dist/scummvm/
+ $(CP) $(DISTPATH)/icon.png dist/scummvm/
+endif
+ $(CP) $(DISTPATH)/READMII dist/scummvm/
+ $(CP) $(srcdir)/AUTHORS dist/scummvm/
+ $(CP) $(srcdir)/COPYING dist/scummvm/
+ $(CP) $(srcdir)/COPYRIGHT dist/scummvm/
+ $(CP) $(srcdir)/NEWS dist/scummvm/
+ $(CP) $(srcdir)/README dist/scummvm/
+ $(CP) $(DIST_FILES_THEMES) dist/scummvm/
+ $(CP) $(DIST_FILES_ENGINEDATA) dist/scummvm/
diff --git a/backends/platform/wii/gx_supp.cpp b/backends/platform/wii/gx_supp.cpp
index 4c7b8ed58a..436deddbb8 100644
--- a/backends/platform/wii/gx_supp.cpp
+++ b/backends/platform/wii/gx_supp.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
* Generic GX Support for Emulators
* softdev 2007
+* dhewg 2008
*
* 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
@@ -21,12 +22,13 @@
* These are pretty standard functions to setup and use GX scaling.
****************************************************************************/
-#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
+#include "gx_supp.h"
+
#define DEFAULT_FIFO_SIZE (256 * 1024)
#define HASPECT 320
@@ -39,18 +41,19 @@ extern "C" {
/*** 2D ***/
static u32 whichfb;
static u32 *xfb[2];
-static GXRModeObj *vmode;
+GXRModeObj *vmode = NULL;
/*** 3D GX ***/
static u8 *gp_fifo;
/*** Texture memory ***/
-static u8 *texturemem;
+static u8 *texturemem = NULL;
static u32 texturesize;
-GXTexObj texobj;
+static GXTexObj texobj;
static Mtx view;
static u16 vwidth, vheight, oldvwidth, oldvheight;
+static float tex_xT = 0.0f, tex_yT = 0.0f;
/* New texture based scaler */
typedef struct tagcamera {
@@ -74,6 +77,10 @@ static camera cam = {
void GX_InitVideo() {
vmode = VIDEO_GetPreferredMode(NULL);
+
+ vmode->viWidth = 678;
+ vmode->viXOrigin = (VI_MAX_WIDTH_PAL - 678) / 2;
+
VIDEO_Configure(vmode);
xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer(vmode));
@@ -93,6 +100,15 @@ void GX_InitVideo() {
VIDEO_WaitVSync();
}
+void GX_SetTexTrans(float xT, float yT) {
+ tex_xT = xT;
+ tex_yT = yT;
+}
+
+void GX_SetCamPosZ(float f) {
+ cam.pos.z = f;
+}
+
/****************************************************************************
* Scaler Support Functions
****************************************************************************/
@@ -128,7 +144,7 @@ static void draw_square(Mtx v) {
Mtx mv;
guMtxIdentity(m);
- guMtxTransApply(m, m, 0, 0, -100);
+ guMtxTransApply(m, m, tex_xT, tex_yT, -100);
guMtxConcat(v, m, mv);
GX_LoadPosMtxImm(mv, GX_PNMTX0);
@@ -144,9 +160,9 @@ static void draw_square(Mtx v) {
* StartGX
****************************************************************************/
void GX_Start(u16 width, u16 height, s16 haspect, s16 vaspect) {
+ static bool inited = false;
Mtx p;
-
- GX_AbortFrame();
+ GXColor gxbackground = { 0, 0, 0, 0xff };
/*** Set new aspect ***/
square[0] = square[9] = -haspect;
@@ -156,9 +172,20 @@ void GX_Start(u16 width, u16 height, s16 haspect, s16 vaspect) {
/*** Allocate 32byte aligned texture memory ***/
texturesize = (width * height) * 2;
+
+ if (texturemem)
+ free(texturemem);
+
texturemem = (u8 *) memalign(32, texturesize);
+ memset(texturemem, 0, texturesize);
- GXColor gxbackground = { 0, 0, 0, 0xff };
+ /*** Setup for first call to scaler ***/
+ oldvwidth = oldvheight = -1;
+
+ if (inited)
+ return;
+
+ inited = true;
/*** Clear out FIFO area ***/
memset(gp_fifo, 0, DEFAULT_FIFO_SIZE);
@@ -184,12 +211,8 @@ void GX_Start(u16 width, u16 height, s16 haspect, s16 vaspect) {
guPerspective(p, 60, 1.33f, 10.0f, 1000.0f);
GX_LoadProjectionMtx(p, GX_PERSPECTIVE);
- memset(texturemem, 0, texturesize);
GX_Flush();
-
- /*** Setup for first call to scaler ***/
- vwidth = vheight = -1;
}
/****************************************************************************
diff --git a/backends/platform/wii/gx_supp.h b/backends/platform/wii/gx_supp.h
index 9393e93a26..108a94f0e7 100644
--- a/backends/platform/wii/gx_supp.h
+++ b/backends/platform/wii/gx_supp.h
@@ -1,6 +1,7 @@
/****************************************************************************
* Generic GX Scaler
* softdev 2007
+* dhewg 2008
*
* 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
@@ -23,11 +24,17 @@
#ifndef _WII_GX_SUPP_H_
#define _WII_GX_SUPP_H_
+#include <gccore.h>
+
#ifdef __cplusplus
extern "C" {
#endif
+extern GXRModeObj *vmode;
+
void GX_InitVideo();
+void GX_SetTexTrans(float xT, float yT);
+void GX_SetCamPosZ(float f);
void GX_Start(u16 width, u16 height, s16 haspect, s16 vaspect);
void GX_Render(u16 width, u16 height, u8 *buffer, u16 pitch);
diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp
index 5753ecefe4..8bb1bff904 100644
--- a/backends/platform/wii/main.cpp
+++ b/backends/platform/wii/main.cpp
@@ -62,7 +62,9 @@ int main(int argc, char *argv[]) {
printf("startup\n");
SYS_SetResetCallback(reset_cb);
+#ifndef GAMECUBE
SYS_SetPowerCallback(power_cb);
+#endif
if (!fatInitDefault()) {
printf("fatInitDefault failed\n");
@@ -75,7 +77,7 @@ int main(int argc, char *argv[]) {
if (!strcmp(buf, "fat:/"))
chdir("/apps/scummvm");
- //fatEnableReadAhead(PI_DEFAULT, 32, 128);
+ fatEnableReadAhead(PI_DEFAULT, 32, 128);
}
g_system = new OSystem_Wii();
diff --git a/backends/platform/wii/osystem.cpp b/backends/platform/wii/osystem.cpp
index 9e708345c5..505f93c820 100644
--- a/backends/platform/wii/osystem.cpp
+++ b/backends/platform/wii/osystem.cpp
@@ -19,8 +19,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "osystem.h"
#include "backends/fs/wii/wii-fs-factory.h"
+#include "common/config-manager.h"
+
+#include "osystem.h"
#include <unistd.h>
@@ -51,7 +53,9 @@ OSystem_Wii::OSystem_Wii() :
_currentHeight(0),
_supportedGraphicsModes(NULL),
- _activeGraphicsMode(-1),
+ _activeGraphicsMode(0),
+
+ _fullscreen(false),
_mouseVisible(false),
_mouseX(0),
@@ -89,11 +93,17 @@ OSystem_Wii::~OSystem_Wii() {
void OSystem_Wii::initBackend() {
_startup_time = gettime();
+
+ char buf[MAXPATHLEN];
+ if (!getcwd(buf, MAXPATHLEN))
+ strcpy(buf, "/");
- _savefile = new DefaultSaveFileManager();
+ _savefile = new DefaultSaveFileManager(buf);
_mixer = new Audio::MixerImpl(this);
_timer = new DefaultTimerManager();
+ _fullscreen = ConfMan.getBool("fullscreen");
+
initGfx();
initSfx();
initEvents();
@@ -108,14 +118,28 @@ void OSystem_Wii::quit() {
}
bool OSystem_Wii::hasFeature(Feature f) {
- return f == kFeatureCursorHasPalette;
+ return (f == kFeatureFullscreenMode) ||
+ (f == kFeatureCursorHasPalette);
}
void OSystem_Wii::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ _fullscreen = enable;
+ setGraphicsMode(_activeGraphicsMode);
+ break;
+ default:
+ break;
+ }
}
bool OSystem_Wii::getFeatureState(Feature f) {
- return false;
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return _fullscreen;
+ default:
+ return false;
+ }
}
uint32 OSystem_Wii::getMillis() {
diff --git a/backends/platform/wii/osystem.h b/backends/platform/wii/osystem.h
index 7fbc560b1a..94c0fa76b3 100644
--- a/backends/platform/wii/osystem.h
+++ b/backends/platform/wii/osystem.h
@@ -22,9 +22,9 @@
#ifndef _WII_OSYSTEM_H_
#define _WII_OSYSTEM_H_
-#include "common/system.h"
#include "base/main.h"
-
+#include "common/system.h"
+#include "common/fs.h"
#include "common/rect.h"
#include "common/events.h"
@@ -73,6 +73,8 @@ private:
OSystem::GraphicsMode *_supportedGraphicsModes;
s32 _activeGraphicsMode;
+ bool _fullscreen;
+
bool _mouseVisible;
s32 _mouseX, _mouseY;
u32 _mouseWidth, _mouseHeight;
@@ -110,7 +112,6 @@ public:
virtual bool getFeatureState(Feature f);
virtual const GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
- bool setGraphicsMode(const char *name);
virtual bool setGraphicsMode(int mode);
virtual int getGraphicsMode() const;
virtual void initSize(uint width, uint height);
diff --git a/backends/platform/wii/osystem_gfx.cpp b/backends/platform/wii/osystem_gfx.cpp
index 1e54233c93..faad41d5f0 100644
--- a/backends/platform/wii/osystem_gfx.cpp
+++ b/backends/platform/wii/osystem_gfx.cpp
@@ -27,7 +27,12 @@
#define MAX_FPS 30
enum GraphicModeID {
- GM_DEFAULT
+ GM_DEFAULT = 0,
+ GM_OVERSCAN1,
+ GM_OVERSCAN2,
+ GM_OVERSCAN3,
+ GM_OVERSCAN4,
+ GM_OVERSCAN5
};
void OSystem_Wii::initGfx() {
@@ -42,6 +47,11 @@ void OSystem_Wii::initGfx() {
_overlayWidth = 640;
_overlayHeight = 480;
+#ifndef GAMECUBE
+ if (CONF_GetAspectRatio() && _fullscreen)
+ _overlayHeight = 360;
+#endif
+
_overlaySize = _overlayWidth * _overlayHeight * 2;
_overlayPixels = (OverlayColor *) memalign(32, _overlaySize);
@@ -51,17 +61,32 @@ void OSystem_Wii::initGfx() {
_cursorPalette = (u16 *) memalign(32, 256 * 2);
memset(_cursorPalette, 0, 256 * 2);
- _supportedGraphicsModes = new OSystem::GraphicsMode[2];
- _supportedGraphicsModes[0].name = strdup("gx");
- _supportedGraphicsModes[0].description = strdup("wii hardware scaler");
+ _supportedGraphicsModes = new OSystem::GraphicsMode[7];
+ _supportedGraphicsModes[0].name = strdup("standard");
+ _supportedGraphicsModes[0].description = strdup("standard");
_supportedGraphicsModes[0].id = GM_DEFAULT;
- _supportedGraphicsModes[1].name = 0;
- _supportedGraphicsModes[1].description = 0;
- _supportedGraphicsModes[1].id = 0;
-
- _texture = (u16 *) memalign(32, _overlaySize);
-
- GX_Start(_overlayWidth, _overlayHeight, 320, 240);
+ _supportedGraphicsModes[1].name = strdup("overscan1");
+ _supportedGraphicsModes[1].description = strdup("overscan 1");
+ _supportedGraphicsModes[1].id = GM_OVERSCAN1;
+ _supportedGraphicsModes[2].name = strdup("overscan2");
+ _supportedGraphicsModes[2].description = strdup("overscan 2");
+ _supportedGraphicsModes[2].id = GM_OVERSCAN2;
+ _supportedGraphicsModes[3].name = strdup("overscan3");
+ _supportedGraphicsModes[3].description = strdup("overscan 3");
+ _supportedGraphicsModes[3].id = GM_OVERSCAN3;
+ _supportedGraphicsModes[4].name = strdup("overscan4");
+ _supportedGraphicsModes[4].description = strdup("overscan 4");
+ _supportedGraphicsModes[4].id = GM_OVERSCAN4;
+ _supportedGraphicsModes[5].name = strdup("overscan5");
+ _supportedGraphicsModes[5].description = strdup("overscan 5");
+ _supportedGraphicsModes[5].id = GM_OVERSCAN5;
+ _supportedGraphicsModes[6].name = 0;
+ _supportedGraphicsModes[6].description = 0;
+ _supportedGraphicsModes[6].id = 0;
+
+ _texture = (u16 *) memalign(32, 640 * 480 * 2);
+
+ setGraphicsMode(_activeGraphicsMode);
}
void OSystem_Wii::deinitGfx() {
@@ -111,13 +136,24 @@ int OSystem_Wii::getDefaultGraphicsMode() const {
return GM_DEFAULT;
}
-bool OSystem_Wii::setGraphicsMode(const char *mode) {
- setGraphicsMode(GM_DEFAULT);
+bool OSystem_Wii::setGraphicsMode(int mode) {
+ s16 xar, yar;
- return true;
-}
+ printf("setGraphicsMode %d\n", mode);
+
+ xar = vmode->viWidth / 2;
+ yar = vmode->xfbHeight / 2;
+
+#ifndef GAMECUBE
+ if (CONF_GetAspectRatio() && !_fullscreen)
+ xar /= 1.33f;
+#endif
+
+ GX_SetCamPosZ(400 - mode * 10);
+ GX_Start(640, 480, xar, yar);
+
+ _activeGraphicsMode = mode;
-bool OSystem_Wii::setGraphicsMode(int mode) {
return true;
}
@@ -129,6 +165,8 @@ void OSystem_Wii::initSize(uint width, uint height) {
if (_gameWidth != width || _gameHeight != height) {
printf("initSize %u %u\n", width, height);
+ assert((width <= 640) && (height <= 480));
+
_gameWidth = width;
_gameHeight = height;
@@ -136,12 +174,15 @@ void OSystem_Wii::initSize(uint width, uint height) {
free(_gamePixels);
_gamePixels = (u8 *) memalign(32, _gameWidth * _gameHeight);
+ memset(_gamePixels, 0, _gameWidth * _gameHeight);
if (!_overlayVisible) {
_currentWidth = _gameWidth;
_currentHeight = _gameHeight;
updateEventScreenResolution();
}
+
+ setGraphicsMode(_activeGraphicsMode);
}
}
@@ -320,6 +361,8 @@ void OSystem_Wii::unlockScreen() {
}
void OSystem_Wii::setShakePos(int shakeOffset) {
+ GX_SetTexTrans(0, (float) -shakeOffset * ((float) vmode->efbHeight /
+ (float) _currentHeight));
}
void OSystem_Wii::showOverlay() {
diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp
index 45310dba88..7f78517762 100644
--- a/backends/platform/wince/CEActionsPocket.cpp
+++ b/backends/platform/wince/CEActionsPocket.cpp
@@ -121,7 +121,7 @@ void CEActionsPocket::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (gameid == "kyra1");
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
@@ -129,11 +129,13 @@ void CEActionsPocket::initInstanceGame() {
bool is_parallaction = (gameid == "parallaction");
bool is_lure = (gameid == "lure");
bool is_feeble = (gameid == "feeble");
+ bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0);
GUI_Actions::initInstanceGame();
// See if a right click mapping could be needed
- if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_samnmax || is_cine || is_touche || is_parallaction)
+ if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob ||
+ is_samnmax || is_cine || is_touche || is_parallaction || is_drascula)
_right_click_needed = true;
// See if a "hide toolbar" mapping could be needed
@@ -145,7 +147,7 @@ void CEActionsPocket::initInstanceGame() {
_key_action[POCKET_ACTION_PAUSE].setKey(VK_SPACE);
_action_enabled[POCKET_ACTION_PAUSE] = true;
// Save
- if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble)
+ if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble)
_action_enabled[POCKET_ACTION_SAVE] = false;
else if (is_queen) {
_action_enabled[POCKET_ACTION_SAVE] = true;
@@ -153,7 +155,7 @@ void CEActionsPocket::initInstanceGame() {
} else if (is_sky) {
_action_enabled[POCKET_ACTION_SAVE] = true;
_key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5);
- } else if (is_cine) {
+ } else if (is_cine || is_drascula) {
_action_enabled[POCKET_ACTION_SAVE] = true;
_key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); // F10
} else if (is_agi) {
@@ -171,7 +173,8 @@ void CEActionsPocket::initInstanceGame() {
// Skip
if (!is_cine && !is_parallaction)
_action_enabled[POCKET_ACTION_SKIP] = true;
- if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_saga || is_kyra || is_touche || is_lure || is_feeble)
+ if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob ||
+ is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula)
_key_action[POCKET_ACTION_SKIP].setKey(VK_ESCAPE);
else
_key_action[POCKET_ACTION_SKIP].setKey(KEY_ALL_SKIP);
@@ -212,7 +215,7 @@ CEActionsPocket::~CEActionsPocket() {
}
bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) {
- static bool keydialogrunning = false;
+ static bool keydialogrunning = false, quitdialog = false;
if (!pushed) {
switch(action) {
@@ -289,12 +292,14 @@ bool CEActionsPocket::perform(GUI::ActionType action, bool pushed) {
_CESystem->move_cursor_right();
return true;
case POCKET_ACTION_QUIT:
- {
+ if (!quitdialog) {
+ quitdialog = true;
GUI::MessageDialog alert(" Are you sure you want to quit ? ", "Yes", "No");
if (alert.runModal() == GUI::kMessageOK)
_mainSystem->quit();
- return true;
+ quitdialog = false;
}
+ return true;
case POCKET_ACTION_BINDKEYS:
if (!keydialogrunning) {
keydialogrunning = true;
diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp
index 97d780d534..0c4113cc0c 100644
--- a/backends/platform/wince/CEActionsSmartphone.cpp
+++ b/backends/platform/wince/CEActionsSmartphone.cpp
@@ -111,7 +111,7 @@ void CEActionsSmartphone::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (gameid == "kyra1");
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
@@ -119,16 +119,18 @@ void CEActionsSmartphone::initInstanceGame() {
bool is_parallaction = (gameid == "parallaction");
bool is_lure = (gameid == "lure");
bool is_feeble = (gameid == "feeble");
+ bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0);
GUI_Actions::initInstanceGame();
// See if a right click mapping could be needed
- if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_samnmax || is_cine || is_touche || is_parallaction)
+ if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob ||
+ is_samnmax || is_cine || is_touche || is_parallaction || is_drascula)
_right_click_needed = true;
// Initialize keys for different actions
// Save
- if (is_simon || is_sword2 || is_gob || is_kyra || is_touche || is_feeble)
+ if (is_simon || is_sword2 || is_gob || is_kyra || is_feeble)
_action_enabled[SMARTPHONE_ACTION_SAVE] = false;
else if (is_queen) {
_action_enabled[SMARTPHONE_ACTION_SAVE] = true;
@@ -136,7 +138,7 @@ void CEActionsSmartphone::initInstanceGame() {
} else if (is_sky) {
_action_enabled[SMARTPHONE_ACTION_SAVE] = true;
_key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5);
- } else if (is_cine) {
+ } else if (is_cine || is_drascula) {
_action_enabled[SMARTPHONE_ACTION_SAVE] = true;
_key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); //F10
} else if (is_agi) {
@@ -151,7 +153,8 @@ void CEActionsSmartphone::initInstanceGame() {
}
// Skip
_action_enabled[SMARTPHONE_ACTION_SKIP] = true;
- if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_saga || is_kyra || is_touche || is_lure || is_feeble)
+ if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob ||
+ is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula)
_key_action[SMARTPHONE_ACTION_SKIP].setKey(VK_ESCAPE);
else
_key_action[SMARTPHONE_ACTION_SKIP].setKey(KEY_ALL_SKIP);
@@ -176,7 +179,7 @@ CEActionsSmartphone::~CEActionsSmartphone() {
}
bool CEActionsSmartphone::perform(GUI::ActionType action, bool pushed) {
- static bool keydialogrunning = false;
+ static bool keydialogrunning = false, quitdialog = false;
if (!pushed) {
switch (action) {
@@ -247,12 +250,14 @@ bool CEActionsSmartphone::perform(GUI::ActionType action, bool pushed) {
_CESystem->smartphone_rotate_display();
return true;
case SMARTPHONE_ACTION_QUIT:
- {
+ if (!quitdialog) {
+ quitdialog = true;
GUI::MessageDialog alert(" Are you sure you want to quit ? ", "Yes", "No");
if (alert.runModal() == GUI::kMessageOK)
_mainSystem->quit();
- return true;
+ quitdialog = false;
}
+ return true;
}
return false;
diff --git a/backends/platform/wince/CELauncherDialog.cpp b/backends/platform/wince/CELauncherDialog.cpp
index edfdad84b3..7e306be114 100644
--- a/backends/platform/wince/CELauncherDialog.cpp
+++ b/backends/platform/wince/CELauncherDialog.cpp
@@ -72,10 +72,10 @@ void CELauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 d
}
}
-void CELauncherDialog::automaticScanDirectory(const FilesystemNode &node) {
+void CELauncherDialog::automaticScanDirectory(const Common::FilesystemNode &node) {
// First check if we have a recognized game in the current directory
- FSList files;
- node.getChildren(files, FilesystemNode::kListFilesOnly);
+ Common::FSList files;
+ node.getChildren(files, Common::FilesystemNode::kListFilesOnly);
// detect
GameList candidates(EngineMan.detectGames(files));
// insert
@@ -85,9 +85,9 @@ void CELauncherDialog::automaticScanDirectory(const FilesystemNode &node) {
addGameToConf(result);
}
// Then recurse on the subdirectories
- FSList dirs;
- node.getChildren(dirs, FilesystemNode::kListDirectoriesOnly);
- for (FSList::const_iterator currentDir = dirs.begin(); currentDir != dirs.end(); ++currentDir)
+ Common::FSList dirs;
+ node.getChildren(dirs, Common::FilesystemNode::kListDirectoriesOnly);
+ for (Common::FSList::const_iterator currentDir = dirs.begin(); currentDir != dirs.end(); ++currentDir)
automaticScanDirectory(*currentDir);
}
diff --git a/backends/platform/wince/CELauncherDialog.h b/backends/platform/wince/CELauncherDialog.h
index 55d177bcb8..a5f3fd0d43 100644
--- a/backends/platform/wince/CELauncherDialog.h
+++ b/backends/platform/wince/CELauncherDialog.h
@@ -36,7 +36,7 @@ public:
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
protected:
void addGame();
- void automaticScanDirectory(const FilesystemNode &node);
+ void automaticScanDirectory(const Common::FilesystemNode &node);
};
typedef GUI::LauncherDialog GUILauncherDialog;
diff --git a/backends/platform/wince/CEkeys/EventsBuffer.cpp b/backends/platform/wince/CEkeys/EventsBuffer.cpp
index 92a21ab7ad..f31a77570f 100644
--- a/backends/platform/wince/CEkeys/EventsBuffer.cpp
+++ b/backends/platform/wince/CEkeys/EventsBuffer.cpp
@@ -36,9 +36,8 @@ namespace CEKEYS {
key->setKey(key->keycode());
ev.type = (pushed ? SDL_KEYDOWN : SDL_KEYUP);
- ev.key.keysym.mod = (SDLMod)key->flags();
+ ev.key.keysym.unicode = (SDLMod)key->flags(); // HACK: put the flags into the unused unicode field
ev.key.keysym.sym = (SDLKey)key->keycode();
- ev.key.keysym.unicode = key->keycode();
ev.key.keysym.mod = KMOD_RESERVED;
return (SDL_PushEvent(&ev) == 0);
}
diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile
index 176971067e..9f040bbed1 100644
--- a/backends/platform/wince/Makefile
+++ b/backends/platform/wince/Makefile
@@ -34,17 +34,19 @@ ENABLE_SWORD1 = STATIC_PLUGIN
ENABLE_SWORD2 = STATIC_PLUGIN
ENABLE_TOUCHE = STATIC_PLUGIN
ENABLE_PARALLACTION = STATIC_PLUGIN
+ENABLE_DRASCULA = STATIC_PLUGIN
#ENABLE_CRUISE = STATIC_PLUGIN
-#ENABLE_DRASCULA = STATIC_PLUGIN
#ENABLE_IGOR = STATIC_PLUGIN
+#ENABLE_M4 = STATIC_PLUGIN
+#ENABLE_MADE = STATIC_PLUGIN
########################################################################
## Pick which libraries you want to use here
USE_MAD = 1
USE_MPEG2 = 1
-USE_TREMOR = 1
-#USE_TREMOLO = 1
+#USE_TREMOR = 1
+USE_TREMOLO = 1
USE_FLAC = 1
USE_ZLIB = 1
@@ -137,7 +139,7 @@ LIBS += -ltremorce
endif
ifdef USE_TREMOLO
-DEFINES += -DUSE_TREMOR -DUSE_VORBIS
+DEFINES += -DUSE_TREMOR -DUSE_VORBIS -DUSE_TREMOLO
INCLUDES += -Ilibs/include/tremolo
LIBS += -llibTremolo
endif
diff --git a/backends/platform/wince/README-WinCE.txt b/backends/platform/wince/README-WinCE.txt
index f4cb00dcfa..86c627d764 100644
--- a/backends/platform/wince/README-WinCE.txt
+++ b/backends/platform/wince/README-WinCE.txt
@@ -1,29 +1,28 @@
ScummVM Windows CE FAQ
Last updated: $Date$
-Release version: 0.11.0
+Release version: 0.12.0
------------------------------------------------------------------------
New in this version
-------------------
-0.11.0
-- Redesigned 'Free Look' action (Pocket PCs)
-In order to accommodate for the requirements of the lure engine, the
-usage characteristics of the 'Free Look' action have been improved. The
-new behavior is available for use in all engines, but is is *strongly*
-recommended for at least when playing 'Lure of the Temptress'. By using
-the new scheme, when in 'Free Look' mode, it is now possible to enter
-left clicks by clicking a second time near the current location of the
-mouse pointer. Left and Right clicks at the current point location
-are also available by using the respective actions' bound key.
+0.12.0:
+- Improved SMUSH support (deprecated 'Smush_force_redraw' option)
+No skipped frames in Full Throttle action sequences. The 'Smush_force_redraw'
+option is not needed/honored anymore.
-- Reduced optimization build
-The ScummVM executable has grown quite large, prohibiting some devices
-from running memory demanding games (or any games at all). Code
-optimization level has been reduced to offset the growth of the executable.
-Games run slightly slower. This will be addressed before next release.
+- Fixed MultiFuntion key in Full Throttle
-- Several bugfixes
+- Improved sound output
+Fixed a long standing bug which led to distorted sound output in all games.
+
+- Switched to faster ogg vorbis library
+Robin Watts' libTremolo is used for ogg vorbis (tremor) replay. Info patch
+by Lostech.
+
+- New right click through double tap inhibiting option
+Check out the 'no_doubletap_rightclick' option if double-tapping as a right
+click input method annoys you. Patch by spookypeanut.
------------------------------------------------------------------------
@@ -109,10 +108,10 @@ and report your success ...
How do I install ScummVM for Windows CE ?
-----------------------------------------
-Simple! Unpack the release package on your desktop pc, then copy all its contents
-to a folder on your device. Typically, you should at least have scummvm.exe,
-modern.ini and modern.zip in the same directory. Finally, upload your beloved games
-and fire it up :-)
+Simple! Unpack the release package on your desktop pc, then copy all its
+contents to a folder on your device. Typically, you should at least have
+scummvm.exe, modern.ini and modern.zip in the same directory. Finally, upload
+your beloved games and fire it up :-)
Some devices (like Pocket PC 2000) require GAPI to be present.
@@ -184,18 +183,19 @@ The following actions are available :
* Right click : acts as a right mouse button click
* Cursor : hide or display the mouse cursor
* Free look : go in or out of free-look mode. In this mode, you can tap
- the screen to look for interesting locations without walking.
- Cling a second time near the pointer's location equals to left click.
+ the screen to look for interesting locations without
+ walking. Click a second time near the pointer's location
+ equals to a left click.
* Zoom up : magnify the upper part of the screen for 640x480 games
rendered on a QVGA device.
* Zoom down : magnify the lower part of the screen for 640x480 games
rendered on a QVGA device.
- * Multi Function : this key performs a different function depending on the game
- : Full Throttle -> win an action sequence (cheat)
- : Fate of Atlantis -> sucker punch (cheat)
- : Bargon -> F1 (start the game)
- : All AGI games -> bring up the predictive input dialog
- * Bind keys : map a key action to a device button
+ * Multi Function : performs a different function depending on the game :
+ Full Throttle -> win an action sequence (cheat)
+ Fate of Atlantis -> sucker punch (cheat)
+ Bargon -> F1 (start the game)
+ All AGI games -> bring up the predictive input dialog
+ * Bind keys map a key action to a device button
* Up,Down,Left :
Right, : emulate mouse/stylus behavior
Left Click :
@@ -245,11 +245,11 @@ the list of available actions for Smartphones:
* Skip : skip a non interactive sequence, the current dialog or
behaves like the ESC key on a regular keyboard
* Zone : switch between the 3 different mouse zones
- * Multi Function : this key performs a different function depending on the game
- : Full Throttle -> win an action sequence (cheat)
- : Fate of Atlantis -> sucker punch (cheat)
- : Bargon -> F1 (start the game)
- : All AGI games -> bring up the predictive input dialog
+ * Multi Function : performs a different function depending on the game
+ Full Throttle -> win an action sequence (cheat)
+ Fate of Atlantis -> sucker punch (cheat)
+ Bargon -> F1 (start the game)
+ All AGI games -> bring up the predictive input dialog
* Bind keys : map a key action to a device button
* Keyboard : hide or display the virtual keyboard
* Rotate : rotate the screen (also rotates dpad keys)
@@ -287,32 +287,34 @@ Some parameters are specific to this port :
Game specific sections (f.e. [monkey2]) - performance options
- * high_sample_rate bool Desktop quality (22 kHz) sound output if set.
- 11 kHz otherwise. The default is 11 kHz.
- If you have a fast device, you can set this to
- true to enjoy better sound effects and music.
+ * high_sample_rate bool Desktop quality (22 kHz) sound output if
+ set. The default is 11 kHz.
+ If you have a fast device, you can set this
+ to true to enjoy better sound effects and
+ music.
* FM_high_quality bool Desktop quality FM synthesis if set. Lower
- quality otherwise. The default is low quality.
- You can change this if you have a fast device.
- * sound_thread_priority int Set the priority of the sound thread (0, 1, 2).
- Depending on the release, this is set to 1
- internally (above normal). If you get sound
- stuttering try setting this to a higher value.
+ quality otherwise. The default is low
+ quality. You can change this if you have a
+ fast device.
+ * sound_thread_priority int Set the priority of the sound thread (0, 1,
+ 2). Depending on the release, this is set
+ to 1 internally (above normal).
+ If you get sound stuttering try setting
+ this to a higher value.
Set to 0 if your device is fast enough or if
- you prefer better audio/video synchronization.
- * Smush_force_redraw int Force a Smush frame redraw every X missed
- frames. Mainly used for Full Throttle action
- sequences. Setting it lower gives more
- priority to screen redraws. Setting it higher
- gives more priority to stylus/keyboard input.
- The default is 30.
+ you prefer better audio/video sync.
Game specific sections (f.e. [monkey2]) - game options
- * landscape int 0: Portrait, 1: Landscape, 2: Inverse Landscape
- You can also use this in the [scummvm] section
- in QVGA Pocket PCs to display the launcher in
- landscape, for example, at startup.
+ * landscape int 0: Portrait, 1: Landscape,
+ 2: Inverse Landscape.
+ You can also use this in the [scummvm]
+ section to display the launcher in landscape
+ for example, at startup.
+ * no_doubletap_rightclick int 1: Turn off the default behavior of
+ simulating a right-click when the screen is
+ double-tapped.
+
[scummvm] section - keys definition
@@ -335,18 +337,18 @@ You can tweak these parameters to customize how the cursor is handled.
consider being repeated.
* repeatX int Number of key repeat events before changing
horizontal cursor behaviour.
- * stepX1 int Horizontal cursor offset value when the key is
- not repeated.
- * stepX2 int Horizontal cursor offset value when the key is
- repeated less than repeatX.
- * stepX3 int Horizontal cursor offset value when the key is
- repeated more than repeatX.
+ * stepX1 int Horizontal cursor offset value when the key
+ is not repeated.
+ * stepX2 int Horizontal cursor offset value when the key
+ is repeated less than repeatX.
+ * stepX3 int Horizontal cursor offset value when the key
+ is repeated more than repeatX.
* repeatY int Number of key repeat events before changing
- vertical cursor behaviour.
+ vertical cursor behavior.
* stepY1 int Vertical cursor offset value when the key is
not repeated.
- * stepY2 int Horizontal cursor offset value when the key is
- repeated less than repeatY.
+ * stepY2 int Horizontal cursor offset value when the key
+ is repeated less than repeatY.
* stepY3 int Vertical cursor offset value when the key is
repeated more than repeatY.
@@ -361,8 +363,8 @@ Game specific questions
I need to press a special key
-----------------------------
-Bring up the virtual keyboard. On Smartphones take a look at the Keyboard action above.
-On Pocket PCs it's easier to double-tap at the top of the screen.
+Bring up the virtual keyboard. On Smartphones take a look at the Keyboard
+action above. On Pocket PCs it's easier to double-tap at the top of the screen.
The panel is obscuring the playfield area
-----------------------------------------
@@ -383,17 +385,18 @@ Bind and use the quit action to quit.
I cannot rotate the screen to landscape/inverse landscape
---------------------------------------------------------
-Depending on the video driver, ScummVM may opt to not provide such functionality.
-In general, when ScummVM starts in normal "portrait" orientation, the device driver
-reports better display characteristics and you should consider launching from portrait.
+Depending on the video driver, ScummVM may opt to not provide such
+functionality. In general, when ScummVM starts in normal "portrait"
+orientation, the device driver reports better display characteristics and you
+should consider launching from portrait.
I'm having problems. Is there diagnostic output available ?
-----------------------------------------------------------
Insert a line in the [scummvm] section of scummvm.ini with the following:
debuglevel=1
-Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files will be
-available at the program directory (see section above).
+Run ScummVM. When it closes scummvm_stdout.txt and scummvm_stderr.txt files
+will be available at the program directory (see section above).
ScummVM crashes and returns to desktop
--------------------------------------
@@ -548,18 +551,19 @@ Use the Multi Function action.
-- AGI engine games --
----------------------
-Do you expect me to play these games on keyboard less devices ?
+Do you expect me to play these games on keyboard-less devices ?
---------------------------------------------------------------
Sure we do :-)
-If you want to get some mileage on your stylus you can use the virtual keyboard.
-There is a very useful alternative though, the AGI engine's predictive input dialog.
-It requires a dictionary to be present. Just tap on the command line or use the
-Multi Function action to bring it up. On Smartphones, when the dialog is shown
-all key mapping is disabled temporarily (including mouse emulation). Input is
-performed either by pressing the phone's numeric keypad keys and dpad enter to
-close the dialog, or by navigating the buttons using the dpad arrows and pressing
-with dpad enter. Check the main Readme file for more information on this.
+If you want to get some mileage on your stylus you can use the virtual
+keyboard. There is a very useful alternative though, the AGI engine's
+predictive input dialog. It requires a dictionary to be present. Just tap on
+the command line or use the Multi Function action to bring it up. On
+Smartphones, when the dialog is shown all key mapping is disabled temporarily
+(including mouse emulation). Input is performed either by pressing the phone's
+numeric keypad keys and dpad enter to close the dialog, or by navigating the
+buttons using the dpad arrows and pressing with dpad enter. Check the main
+Readme file for more information on this.
---------------------------
-- Lure of the Temptress --
@@ -595,8 +599,9 @@ I think I found a bug, ScummVM crashes in ...
See the "Reporting Bugs" section in ScummVM readme.
-If you have a Pocket PC or Handheld PC, be sure to include its resolution (obtained
-on the second dialog displayed on the "About" menu) in your bug report.
+If you have a Pocket PC or Handheld PC, be sure to include its resolution
+(obtained on the second dialog displayed on the "About" menu) in your bug
+report.
If you cannot reproduce this bug on another ScummVM version, you can cross
post your bug report on ScummVM forums.
@@ -619,6 +624,26 @@ http://www.scummvm.org/
Old news follow ...
------------------------------------------------------------------------
+0.11.0:
+- Redesigned 'Free Look' action (Pocket PCs)
+In order to accommodate for the requirements of the lure engine, the
+usage characteristics of the 'Free Look' action have been improved. The
+new behavior is available for use in all engines, but is is *strongly*
+recommended for at least when playing 'Lure of the Temptress'. By using
+the new scheme, when in 'Free Look' mode, it is now possible to enter
+left clicks by clicking a second time near the current location of the
+mouse pointer. Left and Right clicks at the current point location
+are also available by using the respective actions' bound key.
+
+- Reduced optimization build
+The ScummVM executable has grown quite large, prohibiting some devices
+from running memory demanding games (or any games at all). Code
+optimization level has been reduced to offset the growth of the executable.
+Games run slightly slower. This will be addressed before next release.
+
+- Several bugfixes
+
+
0.10.0:
Major improvements have taken place in this version, mostly for behind-
the-scenes stuff. First, we have migrated to GCC for building the Windows
diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp
index c760b1f7df..f03f00bb9a 100644
--- a/backends/platform/wince/missing/missing.cpp
+++ b/backends/platform/wince/missing/missing.cpp
@@ -171,7 +171,7 @@ int _access(const char *path, int mode) {
MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname)/sizeof(TCHAR));
WIN32_FIND_DATA ffd;
- HANDLE h=FindFirstFile(fname, &ffd);
+ HANDLE h = FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
@@ -179,9 +179,14 @@ int _access(const char *path, int mode) {
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {
// WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry
- // hits for files that don't exist. Checking for the same fname twice
+ // hits for files that don't exist. TRIPLE checking for the same fname
// seems to weed out those false positives.
- HANDLE h=FindFirstFile(fname, &ffd);
+ // Exhibited in kyra engine.
+ HANDLE h = FindFirstFile(fname, &ffd);
+ FindClose(h);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1; //Can't find file
+ h = FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp
index 3f16b4fdd1..f09a483086 100644
--- a/backends/platform/wince/wince-sdl.cpp
+++ b/backends/platform/wince/wince-sdl.cpp
@@ -461,7 +461,7 @@ OSystem_WINCE3::OSystem_WINCE3() : OSystem_SDL(),
_orientationLandscape(0), _newOrientation(0), _panelInitialized(false),
_panelVisible(true), _panelStateForced(false), _forceHideMouse(false), _unfilteredkeys(false),
_freeLook(false), _forcePanelInvisible(false), _toolbarHighDrawn(false), _zoomUp(false), _zoomDown(false),
- _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false),
+ _scalersChanged(false), _lastKeyPressed(0), _tapTime(0), _closeClick(false), _noDoubleTapRMB(false),
_saveToolbarState(false), _saveActiveToolbar(NAME_MAIN_PANEL), _rbutton(false), _hasfocus(true),
_usesEmulatedMouse(false), _mouseBackupOld(NULL), _mouseBackupToolbar(NULL), _mouseBackupDim(0)
{
@@ -805,8 +805,16 @@ void OSystem_WINCE3::setupMixer() {
debug(1, "Sound opened OK, mixing at %d Hz", _sampleRate);
// Re-create mixer to match the output rate
+ int vol1 = _mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
+ int vol2 = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
+ int vol3 = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
+ int vol4 = _mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
delete(_mixer);
_mixer = new Audio::MixerImpl(this);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol1);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol2);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol3);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol4);
_mixer->setOutputRate(_sampleRate);
_mixer->setReady(true);
SDL_PauseAudio(0);
@@ -1051,14 +1059,11 @@ void OSystem_WINCE3::update_game_settings() {
panel->setVisible(false);
_saveToolbarState = true;
-
- // Set Smush Force Redraw rate for Full Throttle
- if (!ConfMan.hasKey("Smush_force_redraw")) {
- ConfMan.setInt("Smush_force_redraw", 30);
- ConfMan.flushToDisk();
- }
}
+ if (ConfMan.hasKey("no_doubletap_rightclick"))
+ _noDoubleTapRMB = ConfMan.getBool("no_doubletap_rightclick");
+
compute_sample_rate();
}
@@ -2254,15 +2259,18 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) {
_lastKeyPressed = 0;
event.type = Common::EVENT_PREDICTIVE_DIALOG;
return true;
- }
-
- event.type = Common::EVENT_KEYDOWN;
+ } event.type = Common::EVENT_KEYDOWN;
if (!_unfilteredkeys)
event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
else
event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
+ if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
+ event.kbd.ascii ^= 0x20;
+ event.kbd.flags = Common::KBD_SHIFT;
+ }
+
return true;
case SDL_KEYUP:
@@ -2290,6 +2298,11 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) {
event.kbd.keycode = (Common::KeyCode)mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
event.kbd.ascii = mapKeyCE(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode, _unfilteredkeys);
+ if (ev.key.keysym.mod == KMOD_RESERVED && ev.key.keysym.unicode == KMOD_SHIFT) {
+ event.kbd.ascii ^= 0x20;
+ event.kbd.flags = Common::KBD_SHIFT;
+ }
+
return true;
case SDL_MOUSEMOTION:
@@ -2324,7 +2337,7 @@ bool OSystem_WINCE3::pollEvent(Common::Event &event) {
if (_closeClick && (GetTickCount() - _tapTime < 1000)) {
if (event.mouse.y <= 20 && _panelInitialized) { // top of screen (show panel)
swap_panel_visibility();
- } else { // right click
+ } else if (!_noDoubleTapRMB) { // right click
event.type = Common::EVENT_RBUTTONDOWN;
_rbutton = true;
}
diff --git a/backends/platform/wince/wince-sdl.h b/backends/platform/wince/wince-sdl.h
index 8853c156d8..ece8c9b7b1 100644
--- a/backends/platform/wince/wince-sdl.h
+++ b/backends/platform/wince/wince-sdl.h
@@ -200,6 +200,7 @@ private:
bool _zoomUp; // zooming up mode
bool _zoomDown; // zooming down mode
+ bool _noDoubleTapRMB; // disable double tap -> rmb click
bool _rbutton; // double tap -> right button simulation
bool _closeClick; // flag when taps are spatially close together
diff --git a/backends/saves/compressed/compressed-saves.cpp b/backends/saves/compressed/compressed-saves.cpp
index 150cf5c47d..11cb1689cd 100644
--- a/backends/saves/compressed/compressed-saves.cpp
+++ b/backends/saves/compressed/compressed-saves.cpp
@@ -23,278 +23,14 @@
*
*/
-#include "common/savefile.h"
-#include "common/util.h"
+#include "common/zlib.h"
#include "backends/saves/compressed/compressed-saves.h"
-#if defined(USE_ZLIB)
-#include <zlib.h>
-
-#if ZLIB_VERNUM < 0x1204
-#error Version 1.2.0.4 or newer of zlib is required for this code
-#endif
-
-/**
- * A simple wrapper class which can be used to wrap around an arbitrary
- * other InSaveFile and will then provide on-the-fly decompression support.
- * Assumes the compressed data to be in gzip format.
- */
-class CompressedInSaveFile : public Common::InSaveFile {
-protected:
- enum {
- BUFSIZE = 16384 // 1 << MAX_WBITS
- };
-
- byte _buf[BUFSIZE];
-
- Common::InSaveFile *_wrapped;
- z_stream _stream;
- int _zlibErr;
- uint32 _pos;
- uint32 _origSize;
-
-public:
-
- CompressedInSaveFile(Common::InSaveFile *w) : _wrapped(w) {
- assert(w != 0);
-
- _stream.zalloc = Z_NULL;
- _stream.zfree = Z_NULL;
- _stream.opaque = Z_NULL;
-
- // Verify file header is correct once more
- w->seek(0, SEEK_SET);
- uint16 header = w->readUint16BE();
- assert(header == 0x1F8B ||
- ((header & 0x0F00) == 0x0800 && header % 31 == 0));
-
- if (header == 0x1F8B) {
- // Retrieve the original file size
- w->seek(-4, SEEK_END);
- _origSize = w->readUint32LE();
- } else {
- // Original size not available in zlib format
- _origSize = 0;
- }
- _pos = 0;
- w->seek(0, SEEK_SET);
-
- // Adding 32 to windowBits indicates to zlib that it is supposed to
- // automatically detect whether gzip or zlib headers are used for
- // the compressed file. This feature was added in zlib 1.2.0.4,
- // released 10 August 2003.
- // Note: This is *crucial* for savegame compatibility, do *not* remove!
- _zlibErr = inflateInit2(&_stream, MAX_WBITS + 32);
- if (_zlibErr != Z_OK)
- return;
-
- // Setup input buffer
- _stream.next_in = _buf;
- _stream.avail_in = 0;
- }
-
- ~CompressedInSaveFile() {
- inflateEnd(&_stream);
- delete _wrapped;
- }
-
- bool ioFailed() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); }
- void clearIOFailed() { /* errors here are not recoverable! */ }
-
- uint32 read(void *dataPtr, uint32 dataSize) {
- _stream.next_out = (byte *)dataPtr;
- _stream.avail_out = dataSize;
-
- // Keep going while we get no error
- while (_zlibErr == Z_OK && _stream.avail_out) {
- if (_stream.avail_in == 0 && !_wrapped->eos()) {
- // If we are out of input data: Read more data, if available.
- _stream.next_in = _buf;
- _stream.avail_in = _wrapped->read(_buf, BUFSIZE);
- }
- _zlibErr = inflate(&_stream, Z_NO_FLUSH);
- }
-
- // Update the position counter
- _pos += dataSize - _stream.avail_out;
-
- return dataSize - _stream.avail_out;
- }
-
- bool eos() const {
- return (_zlibErr == Z_STREAM_END);
- //return _pos == _origSize;
- }
- uint32 pos() const {
- return _pos;
- }
- uint32 size() const {
- return _origSize;
- }
- void seek(int32 offset, int whence = SEEK_SET) {
- int32 newPos = 0;
- switch(whence) {
- case SEEK_END:
- newPos = size() - offset;
- break;
- case SEEK_SET:
- newPos = offset;
- break;
- case SEEK_CUR:
- newPos = _pos + offset;
- }
- offset = newPos - _pos;
-
- if (offset < 0)
- error("Backward seeking not supported in compressed savefiles");
-
- // We could implement backward seeking, but it is tricky to do efficiently.
- // A simple solution would be to restart the whole decompression from the
- // start of the file. Or we could decompress the whole file in one go
- // in the constructor, and wrap it into a MemoryReadStream -- but that
- // would be rather wasteful. As long as we don't need it, I'd rather not
- // implement this at all. -- Fingolfin
-
- // Skip the given amount of data (very inefficient if one tries to skip
- // huge amounts of data, but usually client code will only skip a few
- // bytes, so this should be fine.
- byte tmpBuf[1024];
- while (!ioFailed() && offset > 0) {
- offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset));
- }
- }
-};
-
-/**
- * A simple wrapper class which can be used to wrap around an arbitrary
- * other OutSaveFile and will then provide on-the-fly compression support.
- * The compressed data is written in the gzip format.
- */
-class CompressedOutSaveFile : public Common::OutSaveFile {
-protected:
- enum {
- BUFSIZE = 16384 // 1 << MAX_WBITS
- };
-
- byte _buf[BUFSIZE];
- Common::OutSaveFile *_wrapped;
- z_stream _stream;
- int _zlibErr;
-
- void processData(int flushType) {
- // This function is called by both write() and finalize().
- while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) {
- if (_stream.avail_out == 0) {
- if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) {
- _zlibErr = Z_ERRNO;
- break;
- }
- _stream.next_out = _buf;
- _stream.avail_out = BUFSIZE;
- }
- _zlibErr = deflate(&_stream, flushType);
- }
- }
-
-public:
- CompressedOutSaveFile(Common::OutSaveFile *w) : _wrapped(w) {
- assert(w != 0);
- _stream.zalloc = Z_NULL;
- _stream.zfree = Z_NULL;
- _stream.opaque = Z_NULL;
-
- // Adding 16 to windowBits indicates to zlib that it is supposed to
- // write gzip headers. This feature was added in zlib 1.2.0.4,
- // released 10 August 2003.
- // Note: This is *crucial* for savegame compatibility, do *not* remove!
- _zlibErr = deflateInit2(&_stream,
- Z_DEFAULT_COMPRESSION,
- Z_DEFLATED,
- MAX_WBITS + 16,
- 8,
- Z_DEFAULT_STRATEGY);
- assert(_zlibErr == Z_OK);
-
- _stream.next_out = _buf;
- _stream.avail_out = BUFSIZE;
- _stream.avail_in = 0;
- _stream.next_in = 0;
- }
-
- ~CompressedOutSaveFile() {
- finalize();
- deflateEnd(&_stream);
- delete _wrapped;
- }
-
- bool ioFailed() const {
- return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->ioFailed();
- }
-
- void clearIOFailed() {
- // Note: we don't reset the _zlibErr here, as it is not
- // clear in general ho
- _wrapped->clearIOFailed();
- }
-
- void finalize() {
- if (_zlibErr != Z_OK)
- return;
-
- // Process whatever remaining data there is.
- processData(Z_FINISH);
-
- // Since processData only writes out blocks of size BUFSIZE,
- // we may have to flush some stragglers.
- uint remainder = BUFSIZE - _stream.avail_out;
- if (remainder > 0) {
- if (_wrapped->write(_buf, remainder) != remainder) {
- _zlibErr = Z_ERRNO;
- }
- }
-
- // Finalize the wrapped savefile, too
- _wrapped->finalize();
- }
-
- uint32 write(const void *dataPtr, uint32 dataSize) {
- if (ioFailed())
- return 0;
-
- // Hook in the new data ...
- // Note: We need to make a const_cast here, as zlib is not aware
- // of the const keyword.
- _stream.next_in = const_cast<byte *>((const byte *)dataPtr);
- _stream.avail_in = dataSize;
-
- // ... and flush it to disk
- processData(Z_NO_FLUSH);
-
- return dataSize - _stream.avail_in;
- }
-};
-
-#endif // USE_ZLIB
Common::InSaveFile *wrapInSaveFile(Common::InSaveFile *toBeWrapped) {
-#if defined(USE_ZLIB)
- if (toBeWrapped) {
- uint16 header = toBeWrapped->readUint16BE();
- bool isCompressed = (header == 0x1F8B ||
- ((header & 0x0F00) == 0x0800 &&
- header % 31 == 0));
- toBeWrapped->seek(-2, SEEK_CUR);
- if (isCompressed)
- return new CompressedInSaveFile(toBeWrapped);
- }
-#endif
- return toBeWrapped;
+ return Common::wrapCompressedReadStream(toBeWrapped);
}
Common::OutSaveFile *wrapOutSaveFile(Common::OutSaveFile *toBeWrapped) {
-#if defined(USE_ZLIB)
- if (toBeWrapped)
- return new CompressedOutSaveFile(toBeWrapped);
-#endif
- return toBeWrapped;
+ return Common::wrapCompressedWriteStream(toBeWrapped);
}
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 21bc56e441..0cfd265890 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -28,7 +28,6 @@
#include "common/savefile.h"
#include "common/util.h"
#include "common/fs.h"
-#include "common/file.h"
#include "common/config-manager.h"
#include "backends/saves/default/default-saves.h"
#include "backends/saves/compressed/compressed-saves.h"
@@ -37,91 +36,48 @@
#include <string.h>
#include <errno.h>
-#if defined(UNIX) || defined(__SYMBIAN32__)
+#if defined(UNIX)
#include <sys/stat.h>
#endif
-
-class StdioSaveFile : public Common::InSaveFile, public Common::OutSaveFile {
-private:
- FILE *fh;
-public:
- StdioSaveFile(const char *filename, bool saveOrLoad) {
- fh = ::fopen(filename, (saveOrLoad? "wb" : "rb"));
- }
- ~StdioSaveFile() {
- if (fh)
- ::fclose(fh);
- }
-
- bool eos() const { return feof(fh) != 0; }
- bool ioFailed() const { return ferror(fh) != 0; }
- void clearIOFailed() { clearerr(fh); }
-
- bool isOpen() const { return fh != 0; }
-
- uint32 read(void *dataPtr, uint32 dataSize) {
- assert(fh);
- return fread(dataPtr, 1, dataSize, fh);
- }
- uint32 write(const void *dataPtr, uint32 dataSize) {
- assert(fh);
- return fwrite(dataPtr, 1, dataSize, fh);
- }
-
- uint32 pos() const {
- assert(fh);
- return ftell(fh);
- }
- uint32 size() const {
- assert(fh);
- uint32 oldPos = ftell(fh);
- fseek(fh, 0, SEEK_END);
- uint32 length = ftell(fh);
- fseek(fh, oldPos, SEEK_SET);
- return length;
- }
-
- void seek(int32 offs, int whence = SEEK_SET) {
- assert(fh);
- fseek(fh, offs, whence);
- }
-};
-
-static void join_paths(const char *filename, const char *directory,
- char *buf, int bufsize) {
- buf[bufsize-1] = '\0';
- strncpy(buf, directory, bufsize-1);
-
-#ifdef WIN32
- // Fix for Win98 issue related with game directory pointing to root drive ex. "c:\"
- if ((buf[0] != 0) && (buf[1] == ':') && (buf[2] == '\\') && (buf[3] == 0)) {
- buf[2] = 0;
- }
+#ifdef UNIX
+#ifdef MACOSX
+#define DEFAULT_SAVE_PATH "Documents/ScummVM Savegames"
+#else
+#define DEFAULT_SAVE_PATH ".scummvm"
#endif
-
- const int dirLen = strlen(buf);
-
- if (dirLen > 0) {
-#if defined(__MORPHOS__) || defined(__amigaos4__)
- if (buf[dirLen-1] != ':' && buf[dirLen-1] != '/')
#endif
-#if !defined(__GP32__)
- strncat(buf, "/", bufsize-1); // prevent double /
-#endif
+DefaultSaveFileManager::DefaultSaveFileManager() {
+ // Register default savepath
+ // TODO: Remove this code here, and instead leave setting the
+ // default savepath to the ports using this class.
+#ifdef DEFAULT_SAVE_PATH
+ Common::String savePath;
+#if defined(UNIX) && !defined(IPHONE)
+ const char *home = getenv("HOME");
+ if (home && *home && strlen(home) < MAXPATHLEN) {
+ savePath = home;
+ savePath += "/" DEFAULT_SAVE_PATH;
+ ConfMan.registerDefault("savepath", savePath);
}
- strncat(buf, filename, bufsize-1);
+#endif
+#endif // #ifdef DEFAULT_SAVE_PATH
+}
+
+DefaultSaveFileManager::DefaultSaveFileManager(const Common::String &defaultSavepath) {
+ ConfMan.registerDefault("savepath", defaultSavepath);
}
+
Common::StringList DefaultSaveFileManager::listSavefiles(const char *pattern) {
- FilesystemNode savePath(getSavePath());
- FSList savefiles;
+ Common::FilesystemNode savePath(getSavePath());
+ Common::FSList savefiles;
Common::StringList results;
Common::String search(pattern);
if (savePath.lookupFile(savefiles, search, false, true, 0)) {
- for (FSList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) {
+ for (Common::FSList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) {
results.push_back(file->getName());
}
}
@@ -129,10 +85,11 @@ Common::StringList DefaultSaveFileManager::listSavefiles(const char *pattern) {
return results;
}
-void DefaultSaveFileManager::checkPath(const Common::String &path) {
+void DefaultSaveFileManager::checkPath(const Common::FilesystemNode &dir) {
+ const Common::String path = dir.getPath();
clearError();
-#if defined(UNIX) || defined(__SYMBIAN32__)
+#if defined(UNIX)
struct stat sb;
// Check whether the dir exists
@@ -144,11 +101,9 @@ void DefaultSaveFileManager::checkPath(const Common::String &path) {
case EACCES:
setError(SFM_DIR_ACCESS, "Search or write permission denied: "+path);
break;
-#if !defined(__SYMBIAN32__)
case ELOOP:
setError(SFM_DIR_LOOP, "Too many symbolic links encountered while traversing the path: "+path);
break;
-#endif
case ENAMETOOLONG:
setError(SFM_DIR_NAMETOOLONG, "The path name is too long: "+path);
break;
@@ -166,11 +121,9 @@ void DefaultSaveFileManager::checkPath(const Common::String &path) {
case EMLINK:
setError(SFM_DIR_LINKMAX, "The link count of the parent directory would exceed {LINK_MAX}: "+path);
break;
-#if !defined(__SYMBIAN32__)
case ELOOP:
setError(SFM_DIR_LOOP, "Too many symbolic links encountered while traversing the path: "+path);
break;
-#endif
case ENAMETOOLONG:
setError(SFM_DIR_NAMETOOLONG, "The path name is too long: "+path);
break;
@@ -196,23 +149,27 @@ void DefaultSaveFileManager::checkPath(const Common::String &path) {
setError(SFM_DIR_NOTDIR, "The given savepath is not a directory: "+path);
}
}
+#else
+ if (!dir.exists()) {
+ // TODO: We could try to mkdir the directory here; or rather, we could
+ // add a mkdir method to FilesystemNode and invoke that here.
+ setError(SFM_DIR_NOENT, "A component of the path does not exist, or the path is an empty string: "+path);
+ } else if (!dir.isDirectory()) {
+ setError(SFM_DIR_NOTDIR, "The given savepath is not a directory: "+path);
+ }
#endif
}
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const char *filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error.
- char buf[256];
- Common::String savePath = getSavePath();
+ Common::FilesystemNode savePath(getSavePath());
checkPath(savePath);
if (getError() == SFM_NO_ERROR) {
- join_paths(filename, savePath.c_str(), buf, sizeof(buf));
- StdioSaveFile *sf = new StdioSaveFile(buf, false);
+ Common::FilesystemNode file = savePath.getChild(filename);
- if (!sf->isOpen()) {
- delete sf;
- sf = 0;
- }
+ // Open the file for reading
+ Common::SeekableReadStream *sf = file.openForReading();
return wrapInSaveFile(sf);
} else {
@@ -222,18 +179,14 @@ Common::InSaveFile *DefaultSaveFileManager::openForLoading(const char *filename)
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const char *filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error.
- char buf[256];
- Common::String savePath = getSavePath();
+ Common::FilesystemNode savePath(getSavePath());
checkPath(savePath);
if (getError() == SFM_NO_ERROR) {
- join_paths(filename, savePath.c_str(), buf, sizeof(buf));
- StdioSaveFile *sf = new StdioSaveFile(buf, true);
+ Common::FilesystemNode file = savePath.getChild(filename);
- if (!sf->isOpen()) {
- delete sf;
- sf = 0;
- }
+ // Open the file for saving
+ Common::WriteStream *sf = file.openForWriting();
return wrapOutSaveFile(sf);
} else {
@@ -242,18 +195,19 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const char *filename)
}
bool DefaultSaveFileManager::removeSavefile(const char *filename) {
- char buf[256];
clearError();
- Common::String filenameStr;
- join_paths(filename, getSavePath().c_str(), buf, sizeof(buf));
- if (remove(buf) != 0) {
+ Common::FilesystemNode savePath(getSavePath());
+ Common::FilesystemNode file = savePath.getChild(filename);
+
+ // TODO: Add new method FilesystemNode::remove()
+ if (remove(file.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
if (errno == EACCES)
- setError(SFM_DIR_ACCESS, "Search or write permission denied: "+filenameStr);
+ setError(SFM_DIR_ACCESS, "Search or write permission denied: "+file.getName());
if (errno == ENOENT)
- setError(SFM_DIR_NOENT, "A component of the path does not exist, or the path is an empty string: "+filenameStr);
+ setError(SFM_DIR_NOENT, "A component of the path does not exist, or the path is an empty string: "+file.getName());
#endif
return false;
} else {
diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h
index f3e0ec5b35..c02ce588c2 100644
--- a/backends/saves/default/default-saves.h
+++ b/backends/saves/default/default-saves.h
@@ -28,12 +28,16 @@
#include "common/savefile.h"
#include "common/str.h"
+#include "common/fs.h"
/**
* Provides a default savefile manager implementation for common platforms.
*/
class DefaultSaveFileManager : public Common::SaveFileManager {
public:
+ DefaultSaveFileManager();
+ DefaultSaveFileManager(const Common::String &defaultSavepath);
+
virtual Common::StringList listSavefiles(const char *pattern);
virtual Common::InSaveFile *openForLoading(const char *filename);
virtual Common::OutSaveFile *openForSaving(const char *filename);
@@ -51,7 +55,7 @@ protected:
* Checks the given path for read access, existence, etc.
* Sets the internal error and error message accordingly.
*/
- void checkPath(const Common::String &path);
+ void checkPath(const Common::FilesystemNode &dir);
};
#endif
diff --git a/backends/vkeybd/virtual-keyboard.cpp b/backends/vkeybd/virtual-keyboard.cpp
index f76940343e..fab2d80d30 100644
--- a/backends/vkeybd/virtual-keyboard.cpp
+++ b/backends/vkeybd/virtual-keyboard.cpp
@@ -30,6 +30,7 @@
#include "common/config-manager.h"
#include "common/fs.h"
#include "graphics/imageman.h"
+#include "common/unzip.h"
#define KEY_START_CHAR ('[')
#define KEY_END_CHAR (']')
@@ -86,11 +87,6 @@ bool VirtualKeyboard::loadKeyboardPack(String packName) {
vkDir = new FilesystemNode(".");
}
- // HACK/FIXME:
- // - the ImageManager still needs the default directory to be added
- // - would be nice for everything to use FSNodes
- File::addDefaultDirectory(vkDir->getPath());
-
if (vkDir->getChild(packName + ".xml").exists()) {
// uncompressed keyboard pack
@@ -100,28 +96,15 @@ bool VirtualKeyboard::loadKeyboardPack(String packName) {
} else if (vkDir->getChild(packName + ".zip").exists()) {
// compressed keyboard pack
#ifdef USE_ZLIB
- unzFile zipFile = unzOpen(vkDir->getChild(packName + ".zip").getPath().c_str());
- if (zipFile && unzLocateFile(zipFile, (packName + ".xml").c_str(), 2) == UNZ_OK) {
- unz_file_info fileInfo;
- unzOpenCurrentFile(zipFile);
- unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- byte *buffer = (byte *)malloc(fileInfo.uncompressed_size+1 * sizeof(byte));
- assert(buffer);
- memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(byte));
- unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(zipFile);
- if (!_parser->loadBuffer(buffer, fileInfo.uncompressed_size+1, true)) {
- unzClose(zipFile);
+ ZipArchive arch(vkDir->getChild(packName + ".zip").getPath().c_str());
+ if (arch.hasFile(packName + ".xml")) {
+ if (!_parser->loadStream(arch.openFile(packName + ".xml")))
return false;
- }
} else {
warning("Could not find %s.xml file in %s.zip keyboard pack", packName.c_str(), packName.c_str());
- unzClose(zipFile);
return false;
}
- unzClose(zipFile);
-
- ImageMan.addArchive(packName + ".zip");
+ ImageMan.addArchive(vkDir->getChild(packName + ".zip").getPath().c_str());
#else
return false;
#endif
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index ea0e1465b6..410777209f 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -34,22 +34,6 @@
#include "sound/mididrv.h"
-#ifdef IPHONE
-#include "backends/platform/iphone/osys_iphone.h"
-#endif
-
-#ifdef UNIX
-#ifdef MACOSX
-#define DEFAULT_SAVE_PATH "Documents/ScummVM Savegames"
-#else
-#define DEFAULT_SAVE_PATH ".scummvm"
-#endif
-#elif defined(__SYMBIAN32__)
-#define DEFAULT_SAVE_PATH "Savegames"
-#elif defined(PALMOS_MODE)
-#define DEFAULT_SAVE_PATH "/PALM/Programs/ScummVM/Saved"
-#endif
-
#define DETECTOR_TESTING_HACK
namespace Base {
@@ -72,6 +56,7 @@ static const char HELP_STRING[] =
" -h, --help Display a brief help text and exit\n"
" -z, --list-games Display list of supported games and exit\n"
" -t, --list-targets Display list of configured targets and exit\n"
+ " --list-saves=TARGET Display a list of savegames for the game (TARGET) specified\n"
"\n"
" -c, --config=CONFIG Use alternate configuration file\n"
" -p, --path=PATH Path to where the game is installed\n"
@@ -181,9 +166,6 @@ void registerDefaults() {
// Game specific
ConfMan.registerDefault("path", "");
- ConfMan.registerDefault("savepath", "");
-
-// ConfMan.registerDefault("amiga", false);
ConfMan.registerDefault("platform", Common::kPlatformPC);
ConfMan.registerDefault("language", "en");
ConfMan.registerDefault("subtitles", false);
@@ -212,31 +194,6 @@ void registerDefaults() {
ConfMan.registerDefault("joystick_num", -1);
ConfMan.registerDefault("confirm_exit", false);
ConfMan.registerDefault("disable_sdl_parachute", false);
-#ifdef USE_ALSA
- ConfMan.registerDefault("alsa_port", "65:0");
-#endif
-
- // Register default savepath
-#ifdef DEFAULT_SAVE_PATH
- char savePath[MAXPATHLEN];
-#if defined(UNIX) && !defined(IPHONE)
- const char *home = getenv("HOME");
- if (home && *home && strlen(home) < MAXPATHLEN) {
- snprintf(savePath, MAXPATHLEN, "%s/%s", home, DEFAULT_SAVE_PATH);
- ConfMan.registerDefault("savepath", savePath);
- }
-#elif defined(__SYMBIAN32__)
- strcpy(savePath, Symbian::GetExecutablePath());
- strcat(savePath, DEFAULT_SAVE_PATH);
- strcat(savePath, "\\");
- ConfMan.registerDefault("savepath", savePath);
-#elif defined (IPHONE)
- ConfMan.registerDefault("savepath", OSystem_IPHONE::getSavePath());
-
-#elif defined(PALMOS_MODE)
- ConfMan.registerDefault("savepath", DEFAULT_SAVE_PATH);
-#endif
-#endif // #ifdef DEFAULT_SAVE_PATH
ConfMan.registerDefault("record_mode", "none");
ConfMan.registerDefault("record_file_name", "record.bin");
@@ -408,7 +365,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, char **ar
END_OPTION
DO_OPTION('p', "path")
- FilesystemNode path(option);
+ Common::FilesystemNode path(option);
if (!path.exists()) {
usage("Non-existent game path '%s'", option);
} else if (!path.isReadable()) {
@@ -451,7 +408,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, char **ar
END_OPTION
DO_LONG_OPTION("soundfont")
- FilesystemNode path(option);
+ Common::FilesystemNode path(option);
if (!path.exists()) {
usage("Non-existent soundfont path '%s'", option);
} else if (!path.isReadable()) {
@@ -481,7 +438,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, char **ar
END_OPTION
DO_LONG_OPTION("savepath")
- FilesystemNode path(option);
+ Common::FilesystemNode path(option);
if (!path.exists()) {
usage("Non-existent savegames path '%s'", option);
} else if (!path.isWritable()) {
@@ -490,7 +447,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, char **ar
END_OPTION
DO_LONG_OPTION("extrapath")
- FilesystemNode path(option);
+ Common::FilesystemNode path(option);
if (!path.exists()) {
usage("Non-existent extra path '%s'", option);
} else if (!path.isReadable()) {
@@ -508,7 +465,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, char **ar
END_OPTION
DO_LONG_OPTION("themepath")
- FilesystemNode path(option);
+ Common::FilesystemNode path(option);
if (!path.exists()) {
usage("Non-existent theme path '%s'", option);
} else if (!path.isReadable()) {
@@ -666,9 +623,9 @@ static void runDetectorTest() {
gameid = name;
}
- FilesystemNode dir(path);
- FSList files;
- if (!dir.getChildren(files, FilesystemNode::kListAll)) {
+ Common::FilesystemNode dir(path);
+ Common::FSList files;
+ if (!dir.getChildren(files, Common::FilesystemNode::kListAll)) {
printf(" ... invalid path, skipping\n");
continue;
}
@@ -779,7 +736,7 @@ bool processSettings(Common::String &command, Common::StringMap &settings) {
if (!settings.contains("savepath")) {
const char *dir = getenv("SCUMMVM_SAVEPATH");
if (dir && *dir && strlen(dir) < MAXPATHLEN) {
- FilesystemNode saveDir(dir);
+ Common::FilesystemNode saveDir(dir);
if (!saveDir.exists()) {
warning("Non-existent SCUMMVM_SAVEPATH save path. It will be ignored.");
} else if (!saveDir.isWritable()) {
diff --git a/base/main.cpp b/base/main.cpp
index 0222d61764..b7179e7231 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -141,8 +141,16 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St
system.setWindowCaption(caption.c_str());
}
+ // FIXME: at this moment, game path handling is being discussed in the mailing list,
+ // while Common::File is being reworked under the hood. After commit 34444, which
+ // changed the implementation of Common::File (specifically removing usage of fopen
+ // and fOpenNoCase, which implicitly supported backslashes in file names), some games
+ // stopped working. Example of this are the HE games which use subdirectories: Kirben
+ // found this issue on lost-win-demo at first. Thus, in commit 34450, searching the
+ // game path was made recursive as a temporary fix/workaround.
+
// Add the game path to the directory search list
- Common::File::addDefaultDirectory(path);
+ Common::File::addDefaultDirectoryRecursive(path);
// Add extrapath (if any) to the directory search list
if (ConfMan.hasKey("extrapath"))
@@ -187,17 +195,35 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St
// Reset the file/directory mappings
Common::File::resetDefaultDirectories();
- return 0;
+ // Return result (== 0 means no error)
+ return result;
}
static void setupGraphics(OSystem &system) {
+
system.beginGFXTransaction();
// Set the user specified graphics mode (if any).
system.setGraphicsMode(ConfMan.get("gfx_mode").c_str());
system.initSize(320, 200);
+
+ if (ConfMan.hasKey("aspect_ratio"))
+ system.setFeatureState(OSystem::kFeatureAspectRatioCorrection, ConfMan.getBool("aspect_ratio"));
+ if (ConfMan.hasKey("fullscreen"))
+ system.setFeatureState(OSystem::kFeatureFullscreenMode, ConfMan.getBool("fullscreen"));
system.endGFXTransaction();
+ // When starting up launcher for the first time, the user might have specified
+ // a --gui-theme option, to allow that option to be working, we need to initialize
+ // GUI here.
+ // FIXME: Find a nicer way to allow --gui-theme to be working
+ GUI::NewGui::instance();
+
+ // Discard any command line options. Those that affect the graphics
+ // mode and the others (like bootparam etc.) should not
+ // blindly be passed to the first game launched from the launcher.
+ ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear();
+
// Set initial window caption
system.setWindowCaption(gScummVMFullVersion);
@@ -268,16 +294,9 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
system.getEventManager()->init();
// Unless a game was specified, show the launcher dialog
- if (0 == ConfMan.getActiveDomain()) {
+ if (0 == ConfMan.getActiveDomain())
launcherDialog(system);
- // Discard any command line options. Those that affect the graphics
- // mode etc. already have should have been handled by the backend at
- // this point. And the others (like bootparam etc.) should not
- // blindly be passed to the first game launched from the launcher.
- ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear();
- }
-
// FIXME: We're now looping the launcher. This, of course, doesn't
// work as well as it should. In theory everything should be destroyed
// cleanly, so this is now enabled to encourage people to fix bits :)
@@ -291,12 +310,19 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
// Try to run the game
int result = runGame(plugin, system, specialDebug);
- // TODO: We should keep running if starting the selected game failed
- // (so instead of just quitting, show a nice error dialog to the
- // user and let him pick another game).
- if (result == 0)
+
+ // Did an error occur ?
+ if (result != 0) {
+ // TODO: Show an informative error dialog if starting the selected game failed.
+ }
+
+ // Quit unless an error occurred, or Return to launcher was requested
+ if (result == 0 && !g_system->getEventManager()->shouldRTL())
break;
+ // Reset RTL flag in case we want to load another engine
+ g_system->getEventManager()->resetRTL();
+
// Discard any command line options. It's unlikely that the user
// wanted to apply them to *all* games ever launched.
ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear();
diff --git a/base/module.mk b/base/module.mk
index dd89c5fb2d..f12a710920 100644
--- a/base/module.mk
+++ b/base/module.mk
@@ -3,7 +3,6 @@ MODULE := base
MODULE_OBJS := \
main.o \
commandLine.o \
- game.o \
plugins.o \
version.o
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 216c6ef1af..7b372587a1 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -29,6 +29,7 @@
#ifdef DYNAMIC_MODULES
#include "common/config-manager.h"
+#include "common/fs.h"
#endif
// Plugin versioning
@@ -157,9 +158,12 @@ public:
#if defined(UNIX) && defined(USE_ALSA)
LINK_PLUGIN(ALSA)
#endif
- #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__)
+ #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__)
LINK_PLUGIN(SEQ)
#endif
+ #if defined(__MINT__)
+ LINK_PLUGIN(STMIDI)
+ #endif
#if defined(IRIX)
LINK_PLUGIN(DMEDIA)
#endif
@@ -200,11 +204,11 @@ PluginList FilePluginProvider::getPlugins() {
PluginList pl;
// Prepare the list of directories to search
- FSList pluginDirs;
+ Common::FSList pluginDirs;
// Add the default directories
- pluginDirs.push_back(FilesystemNode("."));
- pluginDirs.push_back(FilesystemNode("plugins"));
+ pluginDirs.push_back(Common::FilesystemNode("."));
+ pluginDirs.push_back(Common::FilesystemNode("plugins"));
// Add the provider's custom directories
addCustomDirectories(pluginDirs);
@@ -212,21 +216,21 @@ PluginList FilePluginProvider::getPlugins() {
// Add the user specified directory
Common::String pluginsPath(ConfMan.get("pluginspath"));
if (!pluginsPath.empty())
- pluginDirs.push_back(FilesystemNode(pluginsPath));
+ pluginDirs.push_back(Common::FilesystemNode(pluginsPath));
- FSList::const_iterator dir;
+ Common::FSList::const_iterator dir;
for (dir = pluginDirs.begin(); dir != pluginDirs.end(); dir++) {
// Load all plugins.
// Scan for all plugins in this directory
- FSList files;
- if (!dir->getChildren(files, FilesystemNode::kListFilesOnly)) {
+ Common::FSList files;
+ if (!dir->getChildren(files, Common::FilesystemNode::kListFilesOnly)) {
debug(1, "Couldn't open plugin directory '%s'", dir->getPath().c_str());
continue;
} else {
debug(1, "Reading plugins from plugin directory '%s'", dir->getPath().c_str());
}
- for (FSList::const_iterator i = files.begin(); i != files.end(); ++i) {
+ for (Common::FSList::const_iterator i = files.begin(); i != files.end(); ++i) {
if (isPluginFilename(i->getName())) {
pl.push_back(createPlugin(i->getPath()));
}
@@ -252,9 +256,9 @@ bool FilePluginProvider::isPluginFilename(const Common::String &filename) const
return true;
}
-void FilePluginProvider::addCustomDirectories(FSList &dirs) const {
+void FilePluginProvider::addCustomDirectories(Common::FSList &dirs) const {
#ifdef PLUGIN_DIRECTORY
- dirs.push_back(FilesystemNode(PLUGIN_DIRECTORY));
+ dirs.push_back(Common::FilesystemNode(PLUGIN_DIRECTORY));
#endif
}
@@ -376,7 +380,7 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
return result;
}
-GameList EngineManager::detectGames(const FSList &fslist) const {
+GameList EngineManager::detectGames(const Common::FSList &fslist) const {
GameList candidates;
const EnginePlugin::List &plugins = getPlugins();
diff --git a/base/plugins.h b/base/plugins.h
index 02116f6433..90c4469e4d 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -30,9 +30,10 @@
#include "common/singleton.h"
#include "common/util.h"
-#ifdef DYNAMIC_MODULES
-#include "common/fs.h"
-#endif
+namespace Common {
+ class FSList;
+}
+
/**
* @page pagePlugins An overview of the ScummVM plugin system
@@ -258,7 +259,7 @@ protected:
* @param dirs the reference to the list of directories to be used when
* searching for plugins.
*/
- virtual void addCustomDirectories(FSList &dirs) const;
+ virtual void addCustomDirectories(Common::FSList &dirs) const;
};
#endif // DYNAMIC_MODULES
diff --git a/base/version.cpp b/base/version.cpp
index 8de96d0b78..eabafecc30 100644
--- a/base/version.cpp
+++ b/base/version.cpp
@@ -62,7 +62,12 @@ const char *gScummVMVersionDate = SCUMMVM_VERSION " (" __DATE__ " " __TIME__ ")"
const char *gScummVMFullVersion = "ScummVM " SCUMMVM_VERSION " (" __DATE__ " " __TIME__ ")";
const char *gScummVMFeatures = ""
#ifdef USE_TREMOR
+#ifdef USE_TREMOLO
+ // libTremolo is used on WinCE for better ogg performance
+ "Tremolo "
+#else
"Tremor "
+#endif
#else
#ifdef USE_VORBIS
"Vorbis "
@@ -92,11 +97,5 @@ const char *gScummVMFeatures = ""
#ifdef USE_FLUIDSYNTH
"FluidSynth "
#endif
-
-#ifdef __SYMBIAN32__
-// we want a list of compiled in engines visible in the program,
-// because we also release special builds with only one engine
-#include "backends/platform/symbian/src/main_features.inl"
-#endif
;
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp
index e328cf7787..1b0db4755a 100644
--- a/common/advancedDetector.cpp
+++ b/common/advancedDetector.cpp
@@ -34,7 +34,11 @@
namespace Common {
-using namespace AdvancedDetector;
+/**
+ * A list of pointers to ADGameDescription structs (or subclasses thereof).
+ */
+typedef Array<const ADGameDescription*> ADGameDescList;
+
/**
* Detect games in specified directory.
@@ -78,18 +82,20 @@ static void upgradeTargetIfNecessary(const Common::ADParams &params) {
if (params.obsoleteList == 0)
return;
- const char *gameid = ConfMan.get("gameid").c_str();
+ String gameid = ConfMan.get("gameid");
for (const Common::ADObsoleteGameID *o = params.obsoleteList; o->from; ++o) {
- if (!scumm_stricmp(gameid, o->from)) {
+ if (gameid.equalsIgnoreCase(o->from)) {
gameid = o->to;
- ConfMan.set("gameid", o->to);
+ ConfMan.set("gameid", gameid);
if (o->platform != Common::kPlatformUnknown)
ConfMan.set("platform", Common::getPlatformCode(o->platform));
warning("Target upgraded from %s to %s", o->from, o->to);
+ // WORKAROUND: Fix for bug #1719463: "DETECTOR: Launching
+ // undefined target adds launcher entry"
if (ConfMan.hasKey("id_came_from_command_line")) {
warning("Target came from command line. Skipping save");
} else {
@@ -282,10 +288,10 @@ PluginError AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) c
return kNoError;
}
-typedef HashMap<String, bool> StringSet;
-typedef HashMap<String, int32> IntMap;
+typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> StringSet;
+typedef HashMap<String, int32, IgnoreCase_Hash, IgnoreCase_EqualTo> IntMap;
-static void reportUnknown(StringMap &filesMD5, IntMap &filesSize) {
+static void reportUnknown(const StringMap &filesMD5, const IntMap &filesSize) {
// TODO: This message should be cleaned up / made more specific.
// For example, we should specify at least which engine triggered this.
//
@@ -301,62 +307,64 @@ static void reportUnknown(StringMap &filesMD5, IntMap &filesSize) {
printf("\n");
}
+static ADGameDescList detectGameFilebased(const StringMap &allFiles, const Common::ADParams &params);
+
static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &params, Language language, Platform platform, const Common::String extra) {
- StringSet filesList;
+ StringMap allFiles;
+ StringSet detectFiles;
StringMap filesMD5;
IntMap filesSize;
- IntMap allFiles;
-
- File testFile;
-
- String tstr;
-
- uint i;
- char md5str[32+1];
- bool fileMissing;
const ADGameFileDescription *fileDesc;
const ADGameDescription *g;
const byte *descPtr;
debug(3, "Starting detection");
- // First we compose list of files which we need MD5s for
- for (descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize) {
- g = (const ADGameDescription *)descPtr;
-
- for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
- tstr = String(fileDesc->fileName);
- tstr.toLowercase();
- filesList[tstr] = true;
- }
- }
-
- // Get the information of the existing files
+ // First we compose an efficient to query set of all files in fslist.
+ // Includes nifty stuff like removing trailing dots and ignoring case.
for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
- if (file->isDirectory()) continue;
- tstr = file->getName();
- tstr.toLowercase();
+ if (file->isDirectory())
+ continue;
+
+ String tstr = file->getName();
// Strip any trailing dot
if (tstr.lastChar() == '.')
tstr.deleteLastChar();
- allFiles[tstr] = true;
+ allFiles[tstr] = file->getPath(); // Record the presence of this file
+ }
- debug(3, "+ %s", tstr.c_str());
+ // Compute the set of files for which we need MD5s for. I.e. files which are
+ // included in some ADGameDescription *and* present in fslist.
+ for (descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize) {
+ g = (const ADGameDescription *)descPtr;
- if (!filesList.contains(tstr)) continue;
+ for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
+ String tstr = fileDesc->fileName;
+ if (allFiles.contains(tstr))
+ detectFiles[tstr] = true;
+ }
+ }
+
+ // Get the information for all detection files, if they exist
+ for (StringSet::const_iterator file = detectFiles.begin(); file != detectFiles.end(); ++file) {
+ String fname = file->_key;
- if (!md5_file_string(*file, md5str, params.md5Bytes))
+ debug(3, "+ %s", fname.c_str());
+
+ char md5str[32+1];
+ if (!md5_file_string(allFiles[fname].c_str(), md5str, params.md5Bytes))
continue;
- filesMD5[tstr] = md5str;
+ filesMD5[fname] = md5str;
- debug(3, "> %s: %s", tstr.c_str(), md5str);
+ debug(3, "> %s: %s", fname.c_str(), md5str);
- if (testFile.open(file->getPath())) {
- filesSize[tstr] = (int32)testFile.size();
+ File testFile;
+ if (testFile.open(allFiles[fname])) {
+ filesSize[fname] = (int32)testFile.size();
testFile.close();
}
}
@@ -366,9 +374,10 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p
int maxFilesMatched = 0;
// MD5 based matching
+ uint i;
for (i = 0, descPtr = params.descs; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += params.descItemSize, ++i) {
g = (const ADGameDescription *)descPtr;
- fileMissing = false;
+ bool fileMissing = false;
// Do not even bother to look at entries which do not have matching
// language and platform (if specified).
@@ -377,32 +386,28 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p
continue;
}
- if ((params.flags & kADFlagUseExtraAsHint) && extra != "" && g->extra != extra)
+ if ((params.flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra)
continue;
// Try to match all files for this game
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
- tstr = fileDesc->fileName;
- tstr.toLowercase();
+ String tstr = fileDesc->fileName;
if (!filesMD5.contains(tstr)) {
fileMissing = true;
break;
}
- if (fileDesc->md5 != NULL) {
- if (fileDesc->md5 != filesMD5[tstr]) {
- debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesMD5[tstr].c_str());
- fileMissing = true;
- break;
- }
+
+ if (fileDesc->md5 != NULL && fileDesc->md5 != filesMD5[tstr]) {
+ debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesMD5[tstr].c_str());
+ fileMissing = true;
+ break;
}
- if (fileDesc->fileSize != -1) {
- if (fileDesc->fileSize != filesSize[tstr]) {
- debug(3, "Size Mismatch. Skipping");
- fileMissing = true;
- break;
- }
+ if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSize[tstr]) {
+ debug(3, "Size Mismatch. Skipping");
+ fileMissing = true;
+ break;
}
debug(3, "Matched file: %s", tstr.c_str());
@@ -440,85 +445,68 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p
}
}
- // We've found a match
- if (!matched.empty())
- return matched;
-
- if (!filesMD5.empty())
- reportUnknown(filesMD5, filesSize);
-
- // Filename based fallback
- if (params.fileBasedFallback != 0) {
- const ADFileBasedFallback *ptr = params.fileBasedFallback;
- const char* const* filenames = 0;
-
- // First we create list of files required for detection.
- // The filenames can be different than the MD5 based match ones.
- for (; ptr->desc; ptr++) {
- filenames = ptr->filenames;
- for (; *filenames; filenames++) {
- tstr = String(*filenames);
- tstr.toLowercase();
-
- if (!allFiles.contains(tstr)) {
- if (testFile.open(tstr) || testFile.open(tstr + ".")) {
- allFiles[tstr] = true;
- testFile.close();
- }
- }
- }
- }
-
- // Then we perform the actual filename matching. If there are
- // several matches, only the one with the maximum numbers of
- // files is considered.
- int maxNumMatchedFiles = 0;
- const ADGameDescription *matchedDesc = 0;
-
- ptr = params.fileBasedFallback;
+ // We didn't find a match
+ if (matched.empty()) {
+ if (!filesMD5.empty())
+ reportUnknown(filesMD5, filesSize);
+
+ // Filename based fallback
+ if (params.fileBasedFallback != 0)
+ matched = detectGameFilebased(allFiles, params);
+ }
- for (; ptr->desc; ptr++) {
- const ADGameDescription *agdesc = (const ADGameDescription *)ptr->desc;
- int numMatchedFiles = 0;
- fileMissing = false;
+ return matched;
+}
- filenames = ptr->filenames;
- for (; *filenames; filenames++) {
- if (fileMissing) {
- continue;
- }
+/**
+ * Check for each ADFileBasedFallback record whether all files listed
+ * in it are present. If multiple pass this test, we pick the one with
+ * the maximal number of matching files. In case of a tie, the entry
+ * coming first in the list is chosen.
+ */
+static ADGameDescList detectGameFilebased(const StringMap &allFiles, const Common::ADParams &params) {
+ const ADFileBasedFallback *ptr;
+ const char* const* filenames;
- tstr = String(*filenames);
- tstr.toLowercase();
+ int maxNumMatchedFiles = 0;
+ const ADGameDescription *matchedDesc = 0;
- debug(3, "++ %s", *filenames);
- if (!allFiles.contains(tstr)) {
- fileMissing = true;
- continue;
- }
+ for (ptr = params.fileBasedFallback; ptr->desc; ++ptr) {
+ const ADGameDescription *agdesc = (const ADGameDescription *)ptr->desc;
+ int numMatchedFiles = 0;
+ bool fileMissing = false;
- numMatchedFiles++;
+ for (filenames = ptr->filenames; *filenames; ++filenames) {
+ debug(3, "++ %s", *filenames);
+ if (!allFiles.contains(*filenames)) {
+ fileMissing = true;
+ break;
}
- if (!fileMissing)
- debug(4, "Matched: %s", agdesc->gameid);
+ numMatchedFiles++;
+ }
- if (!fileMissing && numMatchedFiles > maxNumMatchedFiles) {
+ if (!fileMissing) {
+ debug(4, "Matched: %s", agdesc->gameid);
+
+ if (numMatchedFiles > maxNumMatchedFiles) {
matchedDesc = agdesc;
maxNumMatchedFiles = numMatchedFiles;
-
+
debug(4, "and overriden");
}
}
+ }
- if (matchedDesc) { // We got a match
- matched.push_back(matchedDesc);
- if (params.flags & kADFlagPrintWarningOnFileBasedFallback) {
- printf("Your game version has been detected using filename matching as a\n");
- printf("variant of %s.\n", matchedDesc->gameid);
- printf("If this is an original and unmodified version, please report any\n");
- printf("information previously printed by ScummVM to the team.\n");
- }
+ ADGameDescList matched;
+
+ if (matchedDesc) { // We got a match
+ matched.push_back(matchedDesc);
+ if (params.flags & kADFlagPrintWarningOnFileBasedFallback) {
+ printf("Your game version has been detected using filename matching as a\n");
+ printf("variant of %s.\n", matchedDesc->gameid);
+ printf("If this is an original and unmodified version, please report any\n");
+ printf("information previously printed by ScummVM to the team.\n");
}
}
diff --git a/common/advancedDetector.h b/common/advancedDetector.h
index 48b9e213d7..b72b9fbfc4 100644
--- a/common/advancedDetector.h
+++ b/common/advancedDetector.h
@@ -28,8 +28,6 @@
#include "common/fs.h"
#include "common/error.h"
-#include "base/game.h" // For PlainGameDescriptor and GameList
-
#include "engines/metaengine.h"
namespace Common {
@@ -69,11 +67,6 @@ struct ADGameDescription {
};
/**
- * A list of pointers to ADGameDescription structs (or subclasses thereof).
- */
-typedef Array<const ADGameDescription*> ADGameDescList;
-
-/**
* End marker for a table of ADGameDescription structs. Use this to
* terminate a list to be passed to the AdvancedDetector API.
*/
diff --git a/common/archive.cpp b/common/archive.cpp
new file mode 100644
index 0000000000..7e17fdca32
--- /dev/null
+++ b/common/archive.cpp
@@ -0,0 +1,344 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/archive.h"
+#include "common/fs.h"
+#include "common/util.h"
+
+namespace Common {
+
+
+int Archive::matchPattern(StringList &list, const String &pattern) {
+ // Get all "names" (TODO: "files" ?)
+ StringList allNames;
+ getAllNames(allNames);
+
+ int matches = 0;
+
+ // need to match lowercase key
+ String lowercasePattern = pattern;
+ lowercasePattern.toLowercase();
+
+ StringList::iterator it = allNames.begin();
+ for ( ; it != allNames.end(); it++) {
+ if (it->matchString(lowercasePattern)) {
+ list.push_back(*it);
+ matches++;
+ }
+ }
+
+ return matches;
+}
+
+
+FSDirectory::FSDirectory(const FilesystemNode &node, int depth)
+ : _node(node), _cached(false), _depth(depth) {
+}
+
+FSDirectory::FSDirectory(const String &name, int depth)
+ : _node(name), _cached(false), _depth(depth) {
+}
+
+FSDirectory::~FSDirectory() {
+}
+
+FilesystemNode FSDirectory::getFSNode() const {
+ return _node;
+}
+
+FilesystemNode FSDirectory::lookupCache(NodeCache &cache, const String &name) {
+ // make caching as lazy as possible
+ if (!name.empty()) {
+ if (!_cached) {
+ cacheDirectoryRecursive(_node, _depth, "");
+ _cached = true;
+ }
+
+ if (cache.contains(name))
+ return cache[name];
+ }
+
+ return FilesystemNode();
+}
+
+bool FSDirectory::hasFile(const String &name) {
+ if (name.empty() || !_node.isDirectory()) {
+ return false;
+ }
+
+ FilesystemNode node = lookupCache(_fileCache, name);
+ return node.exists();
+}
+
+SeekableReadStream *FSDirectory::openFile(const String &name) {
+ if (name.empty() || !_node.isDirectory()) {
+ return 0;
+ }
+
+ FilesystemNode node = lookupCache(_fileCache, name);
+
+ if (!node.exists()) {
+ warning("FSDirectory::openFile: FilesystemNode does not exist");
+ return 0;
+ } else if (node.isDirectory()) {
+ warning("FSDirectory::openFile: FilesystemNode is a directory");
+ return 0;
+ }
+
+ SeekableReadStream *stream = node.openForReading();
+ if (!stream) {
+ warning("FSDirectory::openFile: Can't create stream for file '%s'", name.c_str());
+ }
+
+ return stream;
+}
+
+FSDirectory *FSDirectory::getSubDirectory(const String &name) {
+ if (name.empty() || !_node.isDirectory()) {
+ return 0;
+ }
+
+ FilesystemNode node = lookupCache(_subDirCache, name);
+ return new FSDirectory(node);
+}
+
+void FSDirectory::cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix) {
+ if (depth <= 0) {
+ return;
+ }
+
+ FSList list;
+ node.getChildren(list, FilesystemNode::kListAll, false);
+
+ FSList::iterator it = list.begin();
+ for ( ; it != list.end(); it++) {
+ String name = prefix + (*it).getName();
+
+ // don't touch name as it might be used for warning messages
+ String lowercaseName = name;
+ lowercaseName.toLowercase();
+
+ // since the hashmap is case insensitive, we need to check for clashes when caching
+ if ((*it).isDirectory()) {
+ if (_subDirCache.contains(lowercaseName)) {
+ warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring sub-directory '%s'", name.c_str());
+ } else {
+ cacheDirectoryRecursive(*it, depth - 1, lowercaseName + "/");
+ _subDirCache[lowercaseName] = *it;
+ }
+ } else {
+ if (_fileCache.contains(lowercaseName)) {
+ warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'", name.c_str());
+ } else {
+ _fileCache[lowercaseName] = *it;
+ }
+ }
+ }
+
+}
+
+int FSDirectory::matchPattern(StringList &list, const String &pattern) {
+ if (!_node.isDirectory())
+ return 0;
+
+ // Cache dir data
+ if (!_cached) {
+ cacheDirectoryRecursive(_node, _depth, "");
+ _cached = true;
+ }
+
+ // Small optimization: Ensure the StringList has to grow at most once
+ list.reserve(list.size() + _fileCache.size());
+
+ // Add all filenames from our cache
+ NodeCache::iterator it = _fileCache.begin();
+ for ( ; it != _fileCache.end(); it++) {
+ if (it->_key.matchString(pattern))
+ list.push_back(it->_key);
+ }
+
+ return _fileCache.size();
+}
+
+int FSDirectory::getAllNames(StringList &list) {
+ if (!_node.isDirectory())
+ return 0;
+
+ // Cache dir data
+ if (!_cached) {
+ cacheDirectoryRecursive(_node, _depth, "");
+ _cached = true;
+ }
+
+ // Small optimization: Ensure the StringList has to grow at most once
+ list.reserve(list.size() + _fileCache.size());
+
+ // Add all filenames from our cache
+ NodeCache::iterator it = _fileCache.begin();
+ for ( ; it != _fileCache.end(); it++) {
+ list.push_back((*it)._key);
+ }
+
+ return _fileCache.size();
+}
+
+
+
+SearchSet::ArchiveList::iterator SearchSet::find(const String &name) const {
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ if ((*it)._name == name) {
+ break;
+ }
+ }
+ return it;
+}
+
+/*
+ Keep the nodes sorted according to descending priorities.
+ In case two or node nodes have the same priority, insertion
+ order prevails.
+*/
+void SearchSet::insert(const Node &node) {
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ if ((*it)._priority < node._priority) {
+ break;
+ }
+ }
+ _list.insert(it, node);
+}
+
+void SearchSet::add(const String& name, ArchivePtr archive, uint priority) {
+ if (find(name) == _list.end()) {
+ Node node = { priority, name, archive };
+ insert(node);
+ } else {
+ warning("SearchSet::add: archive '%s' already present", name.c_str());
+ }
+
+}
+
+void SearchSet::remove(const String& name) {
+ ArchiveList::iterator it = find(name);
+ if (it != _list.end()) {
+ _list.erase(it);
+ }
+}
+
+bool SearchSet::hasArchive(const String &name) const {
+ return (find(name) != _list.end());
+}
+
+void SearchSet::clear() {
+ _list.clear();
+}
+
+void SearchSet::setPriority(const String& name, uint priority) {
+ ArchiveList::iterator it = find(name);
+ if (it == _list.end()) {
+ warning("SearchSet::setPriority: archive '%s' is not present", name.c_str());
+ return;
+ }
+
+ if (priority == (*it)._priority) {
+ return;
+ }
+
+ Node node(*it);
+ _list.erase(it);
+ node._priority = priority;
+ insert(node);
+}
+
+bool SearchSet::hasFile(const String &name) {
+ if (name.empty()) {
+ return false;
+ }
+
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ if ((*it)._arc->hasFile(name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int SearchSet::matchPattern(StringList &list, const String &pattern) {
+ int matches = 0;
+
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ matches += (*it)._arc->matchPattern(list, pattern);
+ }
+
+ return matches;
+}
+
+int SearchSet::getAllNames(StringList &list) {
+ int matches = 0;
+
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ matches += (*it)._arc->getAllNames(list);
+ }
+
+ return matches;
+}
+
+SeekableReadStream *SearchSet::openFile(const String &name) {
+ if (name.empty()) {
+ return 0;
+ }
+
+ ArchiveList::iterator it = _list.begin();
+ for ( ; it != _list.end(); it++) {
+ if ((*it)._arc->hasFile(name)) {
+ return (*it)._arc->openFile(name);
+ }
+ }
+
+ return 0;
+}
+
+
+DECLARE_SINGLETON(SearchManager);
+
+void SearchManager::addArchive(const String &name, ArchivePtr archive) {
+ add(name, archive);
+}
+
+void SearchManager::addDirectory(const String &name, const String &directory) {
+ addDirectoryRecursive(name, 1);
+}
+
+void SearchManager::addDirectoryRecursive(const String &name, const String &directory, int depth) {
+ add(name, SharedPtr<FSDirectory>(new FSDirectory(directory, depth)));
+}
+
+
+} // namespace Common
diff --git a/common/archive.h b/common/archive.h
new file mode 100644
index 0000000000..89ea6a5ce2
--- /dev/null
+++ b/common/archive.h
@@ -0,0 +1,231 @@
+/* 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 COMMON_ARCHIVES_H
+#define COMMON_ARCHIVES_H
+
+#include "common/fs.h"
+#include "common/str.h"
+#include "common/hash-str.h"
+#include "common/list.h"
+#include "common/ptr.h"
+#include "common/singleton.h"
+#include "common/stream.h"
+
+namespace Common {
+
+/**
+ * FilePtr is a convenient way to keep track of a SeekableReadStream without
+ * having to worry about releasing its memory.
+ */
+typedef SharedPtr<SeekableReadStream> FilePtr;
+
+/**
+ * Archive allows searches of (file)names into an arbitrary container.
+ * It also supports opening a file and returning an usable input stream.
+ */
+class Archive {
+public:
+ virtual ~Archive() { }
+
+ /**
+ * Check if a name is present in the Archive. Patterns are not allowed,
+ * as this is meant to be a quick File::exists() replacement.
+ */
+ virtual bool hasFile(const String &name) = 0;
+
+ /**
+ * Add all the names present in the Archive which match pattern to
+ * list. Returned names can be used as parameters to openFile.
+ * Must not remove elements from the list.
+ *
+ * @return the number of names added to list
+ */
+ virtual int matchPattern(StringList &list, const String &pattern);
+
+ /**
+ * Add all the names present in the Archive to list. Returned
+ * names can be used as parameters to openFile.
+ * Must not remove elements from the list.
+ *
+ * @return the number of names added to list
+ */
+ virtual int getAllNames(StringList &list) = 0;
+
+ /**
+ * Create a stream bound to a file in the archive.
+ * @return the newly created input stream
+ */
+ virtual SeekableReadStream *openFile(const String &name) = 0;
+};
+
+
+typedef SharedPtr<Archive> ArchivePtr;
+
+
+/**
+ * FSDirectory models a directory tree from the filesystem and allows users
+ * to access it through the Archive interface. FSDirectory can represent a
+ * single directory, or a tree with specified depth, rooted in a 'base'
+ * directory.
+ * Searching is case-insensitive, as the main intended goal is supporting
+ * retrieval of game data. First case-insensitive match is returned when
+ * searching, thus making FSDirectory heavily dependant on the underlying
+ * FilesystemNode implementation.
+ */
+class FSDirectory : public Archive {
+ FilesystemNode _node;
+
+ // Caches are case insensitive, clashes are dealt with when creating
+ // Key is stored in lowercase.
+ typedef HashMap<String, FilesystemNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache;
+ NodeCache _fileCache, _subDirCache;
+
+ // look for a match
+ FilesystemNode lookupCache(NodeCache &cache, const String &name);
+
+ // cache management
+ void cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix);
+ bool _cached;
+ int _depth;
+
+public:
+ /**
+ * Create a FSDirectory representing a tree with the specified depth. Will result in an
+ * unbound FSDirectory if name is not found on the filesystem or is not a directory.
+ */
+ FSDirectory(const String &name, int depth = 1);
+
+ /**
+ * Create a FSDirectory representing a tree with the specified depth. Will result in an
+ * unbound FSDirectory if node does not exist or is not a directory.
+ */
+ FSDirectory(const FilesystemNode &node, int depth = 1);
+
+ virtual ~FSDirectory();
+
+ /**
+ * This return the underlying FSNode of the FSDirectory.
+ */
+ FilesystemNode getFSNode() const;
+
+ /**
+ * Create a new FSDirectory pointing to a sub directory of the instance.
+ * @return a new FSDirectory instance
+ */
+ FSDirectory *getSubDirectory(const String &name);
+
+ virtual bool hasFile(const String &name);
+ virtual int matchPattern(StringList &list, const String &pattern);
+ virtual int getAllNames(StringList &list);
+ virtual SeekableReadStream *openFile(const String &name);
+};
+
+
+/**
+ * SearchSet enables access to a group of Archives through the Archive interface.
+ * Its intended usage is a situation in which there are no name clashes among names in the
+ * contained Archives, hence the simplistic policy of always looking for the first
+ * match. SearchSet *DOES* guarantee that searches are performed in *DESCENDING*
+ * priority order. In case of conflicting priorities, insertion order prevails.
+ */
+class SearchSet : public Archive {
+ struct Node {
+ uint _priority;
+ String _name;
+ ArchivePtr _arc;
+ };
+ typedef List<Node> ArchiveList;
+ ArchiveList _list;
+
+ ArchiveList::iterator find(const String &name) const;
+
+ // Add an archive keeping the list sorted by ascending priorities.
+ void insert(const Node& node);
+
+public:
+ /**
+ * Add a new archive to the searchable set.
+ */
+ void add(const String& name, ArchivePtr archive, uint priority = 0);
+
+ /**
+ * Remove an archive from the searchable set.
+ */
+ void remove(const String& name);
+
+ /**
+ * Check if a given archive name is already present.
+ */
+ bool hasArchive(const String &name) const;
+
+ /**
+ * Empties the searchable set.
+ */
+ void clear();
+
+ /**
+ * Change the order of searches.
+ */
+ void setPriority(const String& name, uint priority);
+
+ virtual bool hasFile(const String &name);
+ virtual int matchPattern(StringList &list, const String &pattern);
+ virtual int getAllNames(StringList &list);
+
+ /**
+ * Implements openFile from Archive base class. The current policy is
+ * opening the first file encountered that matches the name.
+ */
+ virtual SeekableReadStream *openFile(const String &name);
+};
+
+
+class SearchManager : public Singleton<SearchManager>, public SearchSet {
+public:
+ /**
+ * Add an existing Archive. This is meant to support searching in system-specific
+ * archives, namely the MACOSX/IPHONE bundles.
+ */
+ void addArchive(const String &name, ArchivePtr archive);
+
+ /**
+ * Create and add a FSDirectory by name
+ */
+ void addDirectory(const String &name, const String &directory);
+
+ /**
+ * Create and add a FSDirectory and its subdirectories by name
+ */
+ void addDirectoryRecursive(const String &name, const String &directory, int depth = 4);
+
+};
+
+/** Shortcut for accessing the search manager. */
+#define SearchMan Common::SearchManager::instance()
+
+} // namespace Common
+
+#endif
diff --git a/common/array.h b/common/array.h
index 854ce5b91d..693c024d11 100644
--- a/common/array.h
+++ b/common/array.h
@@ -35,7 +35,7 @@ class Array {
protected:
uint _capacity;
uint _size;
- T *_data;
+ T *_storage;
public:
typedef T *iterator;
@@ -44,41 +44,41 @@ public:
typedef T value_type;
public:
- Array() : _capacity(0), _size(0), _data(0) {}
- Array(const Array<T> &array) : _capacity(0), _size(0), _data(0) {
+ Array() : _capacity(0), _size(0), _storage(0) {}
+ Array(const Array<T> &array) : _capacity(0), _size(0), _storage(0) {
_size = array._size;
_capacity = _size + 32;
- _data = new T[_capacity];
- copy(array._data, array._data + _size, _data);
+ _storage = new T[_capacity];
+ copy(array._storage, array._storage + _size, _storage);
}
~Array() {
- delete[] _data;
+ delete[] _storage;
}
void push_back(const T &element) {
ensureCapacity(_size + 1);
- _data[_size++] = element;
+ _storage[_size++] = element;
}
void push_back(const Array<T> &array) {
ensureCapacity(_size + array._size);
- copy(array._data, array._data + array._size, _data + _size);
+ copy(array._storage, array._storage + array._size, _storage + _size);
_size += array._size;
}
void insert_at(int idx, const T &element) {
assert(idx >= 0 && (uint)idx <= _size);
ensureCapacity(_size + 1);
- copy_backward(_data + idx, _data + _size, _data + _size + 1);
- _data[idx] = element;
+ copy_backward(_storage + idx, _storage + _size, _storage + _size + 1);
+ _storage[idx] = element;
_size++;
}
T remove_at(int idx) {
assert(idx >= 0 && (uint)idx < _size);
- T tmp = _data[idx];
- copy(_data + idx + 1, _data + _size, _data + idx);
+ T tmp = _storage[idx];
+ copy(_storage + idx + 1, _storage + _size, _storage + idx);
_size--;
return tmp;
}
@@ -87,23 +87,23 @@ public:
T& operator[](int idx) {
assert(idx >= 0 && (uint)idx < _size);
- return _data[idx];
+ return _storage[idx];
}
const T& operator[](int idx) const {
assert(idx >= 0 && (uint)idx < _size);
- return _data[idx];
+ return _storage[idx];
}
Array<T>& operator=(const Array<T> &array) {
if (this == &array)
return *this;
- delete[] _data;
+ delete[] _storage;
_size = array._size;
_capacity = _size + 32;
- _data = new T[_capacity];
- copy(array._data, array._data + _size, _data);
+ _storage = new T[_capacity];
+ copy(array._storage, array._storage + _size, _storage);
return *this;
}
@@ -113,8 +113,8 @@ public:
}
void clear() {
- delete[] _data;
- _data = 0;
+ delete[] _storage;
+ _storage = 0;
_size = 0;
_capacity = 0;
}
@@ -125,33 +125,33 @@ public:
iterator begin() {
- return _data;
+ return _storage;
}
iterator end() {
- return _data + _size;
+ return _storage + _size;
}
const_iterator begin() const {
- return _data;
+ return _storage;
}
const_iterator end() const {
- return _data + _size;
+ return _storage + _size;
}
void reserve(uint newCapacity) {
if (newCapacity <= _capacity)
return;
- T *old_data = _data;
+ T *old_storage = _storage;
_capacity = newCapacity;
- _data = new T[newCapacity];
+ _storage = new T[newCapacity];
- if (old_data) {
+ if (old_storage) {
// Copy old data
- copy(old_data, old_data + _size, _data);
- delete[] old_data;
+ copy(old_storage, old_storage + _size, _storage);
+ delete[] old_storage;
}
}
@@ -159,14 +159,14 @@ public:
if (newSize == _size)
return;
- T *old_data = _data;
+ T *old_storage = _storage;
_capacity = newSize;
- _data = new T[newSize];
- if (old_data) {
+ _storage = new T[newSize];
+ if (old_storage) {
// Copy old data
int cnt = (_size < newSize ? _size : newSize);
- copy(old_data, old_data + cnt, _data);
- delete[] old_data;
+ copy(old_storage, old_storage + cnt, _storage);
+ delete[] old_storage;
}
_size = newSize;
}
diff --git a/common/config-file.cpp b/common/config-file.cpp
index 9f54c9ddde..c3764a02da 100644
--- a/common/config-file.cpp
+++ b/common/config-file.cpp
@@ -77,7 +77,6 @@ bool ConfigFile::loadFromSaveFile(const char *filename) {
}
bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
- char buf[MAXLINELEN];
Section section;
KeyValue kv;
String comment;
@@ -86,18 +85,21 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
// TODO: Detect if a section occurs multiple times (or likewise, if
// a key occurs multiple times inside one section).
- while (!stream.eos()) {
+ while (!stream.eos() && !stream.ioFailed()) {
lineno++;
- if (!stream.readLine(buf, MAXLINELEN))
- break;
- if (buf[0] == '#') {
+ // Read a line
+ String line = stream.readLine();
+
+ if (line.size() == 0) {
+ // Do nothing
+ } else if (line[0] == '#') {
// Accumulate comments here. Once we encounter either the start
// of a new section, or a key-value-pair, we associate the value
// of the 'comment' variable with that entity.
- comment += buf;
+ comment += line;
comment += "\n";
- } else if (buf[0] == '(') {
+ } else if (line[0] == '(') {
// HACK: The following is a hack added by Kirben to support the
// "map.ini" used in the HE SCUMM game "SPY Fox in Hold the Mustard".
//
@@ -105,11 +107,11 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
// but the current design of this class doesn't allow to do that
// in a nice fashion (a "isMustard" parameter is *not* a nice
// solution).
- comment += buf;
+ comment += line;
comment += "\n";
- } else if (buf[0] == '[') {
+ } else if (line[0] == '[') {
// It's a new section which begins here.
- char *p = buf + 1;
+ const char *p = line.c_str() + 1;
// Get the section name, and check whether it's valid (that
// is, verify that it only consists of alphanumerics,
// dashes and underscores).
@@ -121,23 +123,25 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
else if (*p != ']')
error("ConfigFile::loadFromStream: Invalid character '%c' occured in section name in line %d", *p, lineno);
- *p = 0;
-
// Previous section is finished now, store it.
if (!section.name.empty())
_sections.push_back(section);
- section.name = buf + 1;
+ section.name = String(line.c_str() + 1, p);
section.keys.clear();
section.comment = comment;
comment.clear();
assert(isValidName(section.name));
} else {
- // Skip leading & trailing whitespaces
- char *t = rtrim(ltrim(buf));
-
- // Skip empty lines
+ // This line should be a line with a 'key=value' pair, or an empty one.
+
+ // Skip leading whitespaces
+ const char *t = line.c_str();
+ while (isspace(*t))
+ t++;
+
+ // Skip empty lines / lines with only whitespace
if (*t == 0)
continue;
@@ -146,14 +150,20 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
error("ConfigFile::loadFromStream: Key/value pair found outside a section in line %d", lineno);
}
- // Split string at '=' into 'key' and 'value'.
- char *p = strchr(t, '=');
+ // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter.
+ const char *p = strchr(t, '=');
if (!p)
- error("ConfigFile::loadFromStream: Junk found in line line %d: '%s'", lineno, t);
- *p = 0;
+ error("Config file buggy: Junk found in line line %d: '%s'", lineno, t);
+
+ // Extract the key/value pair
+ kv.key = String(t, p);
+ kv.value = String(p + 1);
+
+ // Trim of spaces
+ kv.key.trim();
+ kv.value.trim();
- kv.key = rtrim(t);
- kv.value = ltrim(p + 1);
+ // Store comment
kv.comment = comment;
comment.clear();
@@ -225,7 +235,7 @@ bool ConfigFile::saveToStream(WriteStream &stream) {
void ConfigFile::removeSection(const String &section) {
assert(isValidName(section));
for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
- if (!scumm_stricmp(section.c_str(), i->name.c_str())) {
+ if (section.equalsIgnoreCase(i->name)) {
_sections.erase(i);
return;
}
@@ -318,7 +328,7 @@ const ConfigFile::SectionKeyList ConfigFile::getKeys(const String &section) cons
ConfigFile::Section *ConfigFile::getSection(const String &section) {
for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) {
- if (!scumm_stricmp(section.c_str(), i->name.c_str())) {
+ if (section.equalsIgnoreCase(i->name)) {
return &(*i);
}
}
@@ -327,7 +337,7 @@ ConfigFile::Section *ConfigFile::getSection(const String &section) {
const ConfigFile::Section *ConfigFile::getSection(const String &section) const {
for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) {
- if (!scumm_stricmp(section.c_str(), i->name.c_str())) {
+ if (section.equalsIgnoreCase(i->name)) {
return &(*i);
}
}
@@ -340,7 +350,7 @@ bool ConfigFile::Section::hasKey(const String &key) const {
const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const {
for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
- if (!scumm_stricmp(key.c_str(), i->key.c_str())) {
+ if (key.equalsIgnoreCase(i->key)) {
return &(*i);
}
}
@@ -349,7 +359,7 @@ const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const
void ConfigFile::Section::setKey(const String &key, const String &value) {
for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
- if (!scumm_stricmp(key.c_str(), i->key.c_str())) {
+ if (key.equalsIgnoreCase(i->key)) {
i->value = value;
return;
}
@@ -363,7 +373,7 @@ void ConfigFile::Section::setKey(const String &key, const String &value) {
void ConfigFile::Section::removeKey(const String &key) {
for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) {
- if (!scumm_stricmp(key.c_str(), i->key.c_str())) {
+ if (key.equalsIgnoreCase(i->key)) {
keys.erase(i);
return;
}
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index 044474a927..b741757cc5 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -23,38 +23,13 @@
*
*/
-#if defined(WIN32)
-#include <windows.h>
-// winnt.h defines ARRAYSIZE, but we want our own one...
-#undef ARRAYSIZE
-#endif
-
#include "common/config-manager.h"
#include "common/file.h"
#include "common/util.h"
+#include "common/system.h"
DECLARE_SINGLETON(Common::ConfigManager);
-#ifdef __PLAYSTATION2__
-#include "backends/platform/ps2/systemps2.h"
-#endif
-
-#ifdef IPHONE
-#include "backends/platform/iphone/osys_iphone.h"
-#endif
-
-#if defined(UNIX)
-#ifdef MACOSX
-#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences"
-#else
-#define DEFAULT_CONFIG_FILE ".scummvmrc"
-#endif
-#else
-#define DEFAULT_CONFIG_FILE "scummvm.ini"
-#endif
-
-#define MAXLINELEN 256
-
static bool isValidDomainName(const Common::String &domName) {
const char *p = domName.c_str();
while (*p && (isalnum(*p) || *p == '-' || *p == '_'))
@@ -85,238 +60,175 @@ ConfigManager::ConfigManager()
void ConfigManager::loadDefaultConfigFile() {
- char configFile[MAXPATHLEN];
- // GP2X is Linux based but Home dir can be read only so do not use it and put the config in the executable dir.
- // On the iPhone, the home dir of the user when you launch the app from the Springboard, is /. Which we don't want.
-#if defined(UNIX) && !defined(GP2X) && !defined(IPHONE)
- const char *home = getenv("HOME");
- if (home != NULL && strlen(home) < MAXPATHLEN)
- snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE);
- else
- strcpy(configFile, DEFAULT_CONFIG_FILE);
-#else
- #if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
- OSVERSIONINFO win32OsVersion;
- ZeroMemory(&win32OsVersion, sizeof(OSVERSIONINFO));
- win32OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&win32OsVersion);
- // Check for non-9X version of Windows.
- if (win32OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) {
- // Use the Application Data directory of the user profile.
- if (win32OsVersion.dwMajorVersion >= 5) {
- if (!GetEnvironmentVariable("APPDATA", configFile, sizeof(configFile)))
- error("Unable to access application data directory");
- } else {
- if (!GetEnvironmentVariable("USERPROFILE", configFile, sizeof(configFile)))
- error("Unable to access user profile directory");
+ // Open the default config file
+ SeekableReadStream *stream = g_system->openConfigFileForReading();
+ _filename.clear(); // clear the filename to indicate that we are using the default config file
- strcat(configFile, "\\Application Data");
- CreateDirectory(configFile, NULL);
- }
+ // ... load it, if available ...
+ if (stream)
+ loadFromStream(*stream);
+
+ // ... and close it again.
+ delete stream;
- strcat(configFile, "\\ScummVM");
- CreateDirectory(configFile, NULL);
- strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
-
- if (fopen(configFile, "r") == NULL) {
- // Check windows directory
- char oldConfigFile[MAXPATHLEN];
- GetWindowsDirectory(oldConfigFile, MAXPATHLEN);
- strcat(oldConfigFile, "\\" DEFAULT_CONFIG_FILE);
- if (fopen(oldConfigFile, "r")) {
- printf("The default location of the config file (scummvm.ini) in ScummVM has changed,\n");
- printf("under Windows NT4/2000/XP/Vista. You may want to consider moving your config\n");
- printf("file from the old default location:\n");
- printf("%s\n", oldConfigFile);
- printf("to the new default location:\n");
- printf("%s\n\n", configFile);
- strcpy(configFile, oldConfigFile);
- }
- }
- } else {
- // Check windows directory
- GetWindowsDirectory(configFile, MAXPATHLEN);
- strcat(configFile, "\\" DEFAULT_CONFIG_FILE);
- }
-
- #elif defined(PALMOS_MODE)
- strcpy(configFile,"/PALM/Programs/ScummVM/" DEFAULT_CONFIG_FILE);
- #elif defined(IPHONE)
- strcpy(configFile, OSystem_IPHONE::getConfigPath());
- #elif defined(__PLAYSTATION2__)
- ((OSystem_PS2*)g_system)->makeConfigPath(configFile);
- #elif defined(__PSP__)
- strcpy(configFile, "ms0:/" DEFAULT_CONFIG_FILE);
- #elif defined (__SYMBIAN32__)
- strcpy(configFile, Symbian::GetExecutablePath());
- strcat(configFile, DEFAULT_CONFIG_FILE);
- #else
- strcpy(configFile, DEFAULT_CONFIG_FILE);
- #endif
-#endif
-
- loadConfigFile(configFile);
flushToDisk();
}
void ConfigManager::loadConfigFile(const String &filename) {
- _appDomain.clear();
- _gameDomains.clear();
- _transientDomain.clear();
-
_filename = filename;
- _domainSaveOrder.clear();
- loadFile(_filename);
- printf("Using configuration file: %s\n", _filename.c_str());
-}
-void ConfigManager::loadFile(const String &filename) {
File cfg_file;
-
if (!cfg_file.open(filename)) {
printf("Creating configuration file: %s\n", filename.c_str());
} else {
- String domain;
- String comment;
- int lineno = 0;
-
- // TODO: Detect if a domain occurs multiple times (or likewise, if
- // a key occurs multiple times inside one domain).
-
- while (!cfg_file.eof() && !cfg_file.ioFailed()) {
- lineno++;
-
- // Read a line
- String line;
- while (line.lastChar() != '\n') {
- char buf[MAXLINELEN];
- if (!cfg_file.readLine_NEW(buf, MAXLINELEN))
- break;
- line += buf;
+ printf("Using configuration file: %s\n", _filename.c_str());
+ loadFromStream(cfg_file);
+ }
+}
+
+void ConfigManager::loadFromStream(SeekableReadStream &stream) {
+ String domain;
+ String comment;
+ int lineno = 0;
+
+ _appDomain.clear();
+ _gameDomains.clear();
+ _transientDomain.clear();
+ _domainSaveOrder.clear();
+
+ // TODO: Detect if a domain occurs multiple times (or likewise, if
+ // a key occurs multiple times inside one domain).
+
+ while (!stream.eos() && !stream.ioFailed()) {
+ lineno++;
+
+ // Read a line
+ String line = stream.readLine();
+
+ if (line.size() == 0) {
+ // Do nothing
+ } else if (line[0] == '#') {
+ // Accumulate comments here. Once we encounter either the start
+ // of a new domain, or a key-value-pair, we associate the value
+ // of the 'comment' variable with that entity.
+ comment += line;
+ comment += "\n";
+ } else if (line[0] == '[') {
+ // It's a new domain which begins here.
+ const char *p = line.c_str() + 1;
+ // Get the domain name, and check whether it's valid (that
+ // is, verify that it only consists of alphanumerics,
+ // dashes and underscores).
+ while (*p && (isalnum(*p) || *p == '-' || *p == '_'))
+ p++;
+
+ if (*p == '\0')
+ error("Config file buggy: missing ] in line %d", lineno);
+ else if (*p != ']')
+ error("Config file buggy: Invalid character '%c' occured in section name in line %d", *p, lineno);
+
+ domain = String(line.c_str() + 1, p);
+
+ // Store domain comment
+ if (domain == kApplicationDomain) {
+ _appDomain.setDomainComment(comment);
+ } else {
+ _gameDomains[domain].setDomainComment(comment);
}
+ comment.clear();
- if (line.size() == 0) {
- // Do nothing
- } else if (line[0] == '#') {
- // Accumulate comments here. Once we encounter either the start
- // of a new domain, or a key-value-pair, we associate the value
- // of the 'comment' variable with that entity.
- comment += line;
- } else if (line[0] == '[') {
- // It's a new domain which begins here.
- const char *p = line.c_str() + 1;
- // Get the domain name, and check whether it's valid (that
- // is, verify that it only consists of alphanumerics,
- // dashes and underscores).
- while (*p && (isalnum(*p) || *p == '-' || *p == '_'))
- p++;
-
- switch (*p) {
- case '\0':
- error("Config file buggy: missing ] in line %d", lineno);
- break;
- case ']':
- domain = String(line.c_str() + 1, p - (line.c_str() + 1));
- //domain = String(line.c_str() + 1, p); // TODO: Pending Common::String changes
- break;
- default:
- error("Config file buggy: Invalid character '%c' occured in domain name in line %d", *p, lineno);
- }
-
- // Store domain comment
- if (domain == kApplicationDomain) {
- _appDomain.setDomainComment(comment);
- } else {
- _gameDomains[domain].setDomainComment(comment);
- }
- comment.clear();
-
- _domainSaveOrder.push_back(domain);
+ _domainSaveOrder.push_back(domain);
+ } else {
+ // This line should be a line with a 'key=value' pair, or an empty one.
+
+ // Skip leading whitespaces
+ const char *t = line.c_str();
+ while (isspace(*t))
+ t++;
+
+ // Skip empty lines / lines with only whitespace
+ if (*t == 0)
+ continue;
+
+ // If no domain has been set, this config file is invalid!
+ if (domain.empty()) {
+ error("Config file buggy: Key/value pair found outside a domain in line %d", lineno);
+ }
+
+ // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter.
+ const char *p = strchr(t, '=');
+ if (!p)
+ error("Config file buggy: Junk found in line line %d: '%s'", lineno, t);
+
+ // Extract the key/value pair
+ String key(t, p);
+ String value(p + 1);
+
+ // Trim of spaces
+ key.trim();
+ value.trim();
+
+ // Finally, store the key/value pair in the active domain
+ set(key, value, domain);
+
+ // Store comment
+ if (domain == kApplicationDomain) {
+ _appDomain.setKVComment(key, comment);
} else {
- // This line should be a line with a 'key=value' pair, or an empty one.
-
- // Skip leading whitespaces
- const char *t = line.c_str();
- while (isspace(*t))
- t++;
-
- // Skip empty lines / lines with only whitespace
- if (*t == 0)
- continue;
-
- // If no domain has been set, this config file is invalid!
- if (domain.empty()) {
- error("Config file buggy: Key/value pair found outside a domain in line %d", lineno);
- }
-
- // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter.
- const char *p = strchr(t, '=');
- if (!p)
- error("Config file buggy: Junk found in line line %d: '%s'", lineno, t);
-
- // Trim spaces before the '=' to obtain the key
- const char *p2 = p;
- while (p2 > t && isspace(*(p2-1)))
- p2--;
- String key(t, p2 - t);
-
- // Skip spaces after the '='
- t = p + 1;
- while (isspace(*t))
- t++;
-
- // Trim trailing spaces
- p2 = t + strlen(t);
- while (p2 > t && isspace(*(p2-1)))
- p2--;
-
- String value(t, p2 - t);
-
- // Finally, store the key/value pair in the active domain
- set(key, value, domain);
-
- // Store comment
- if (domain == kApplicationDomain) {
- _appDomain.setKVComment(key, comment);
- } else {
- _gameDomains[domain].setKVComment(key, comment);
- }
- comment.clear();
+ _gameDomains[domain].setKVComment(key, comment);
}
+ comment.clear();
}
}
}
void ConfigManager::flushToDisk() {
#ifndef __DC__
- DumpFile cfg_file;
+ WriteStream *stream;
- if (!cfg_file.open(_filename)) {
- warning("Unable to write configuration file: %s", _filename.c_str());
+ if (_filename.empty()) {
+ // Write to the default config file
+ stream = g_system->openConfigFileForWriting();
+ if (!stream) // If writing to the config file is not possible, do nothing
+ return;
} else {
- // First write the domains in _domainSaveOrder, in that order.
- // Note: It's possible for _domainSaveOrder to list domains which
- // are not present anymore.
- StringList::const_iterator i;
- for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) {
- if (kApplicationDomain == *i) {
- writeDomain(cfg_file, *i, _appDomain);
- } else if (_gameDomains.contains(*i)) {
- writeDomain(cfg_file, *i, _gameDomains[*i]);
- }
+ DumpFile *dump = new DumpFile();
+ assert(dump);
+
+ if (!dump->open(_filename)) {
+ warning("Unable to write configuration file: %s", _filename.c_str());
+ delete dump;
+ return;
}
+
+ stream = dump;
+ }
- DomainMap::const_iterator d;
+ // First write the domains in _domainSaveOrder, in that order.
+ // Note: It's possible for _domainSaveOrder to list domains which
+ // are not present anymore.
+ StringList::const_iterator i;
+ for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) {
+ if (kApplicationDomain == *i) {
+ writeDomain(*stream, *i, _appDomain);
+ } else if (_gameDomains.contains(*i)) {
+ writeDomain(*stream, *i, _gameDomains[*i]);
+ }
+ }
+ DomainMap::const_iterator d;
- // Now write the domains which haven't been written yet
- if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kApplicationDomain) == _domainSaveOrder.end())
- writeDomain(cfg_file, kApplicationDomain, _appDomain);
- for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) {
- if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end())
- writeDomain(cfg_file, d->_key, d->_value);
- }
+
+ // Now write the domains which haven't been written yet
+ if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kApplicationDomain) == _domainSaveOrder.end())
+ writeDomain(*stream, kApplicationDomain, _appDomain);
+ for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) {
+ if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end())
+ writeDomain(*stream, d->_key, d->_value);
}
+
+ delete stream;
+
#endif // !__DC__
}
@@ -324,6 +236,12 @@ void ConfigManager::writeDomain(WriteStream &stream, const String &name, const D
if (domain.empty())
return; // Don't bother writing empty domains.
+ // WORKAROUND: Fix for bug #1972625 "ALL: On-the-fly targets are
+ // written to the config file": Do not save domains that came from
+ // the command line
+ if (domain.contains("id_came_from_command_line"))
+ return;
+
String comment;
// Write domain comment (if any)
diff --git a/common/config-manager.h b/common/config-manager.h
index bebb59b539..9e5b88a073 100644
--- a/common/config-manager.h
+++ b/common/config-manager.h
@@ -36,7 +36,7 @@
namespace Common {
class WriteStream;
-
+class SeekableReadStream;
/**
* The (singleton) configuration manager, used to query & set configuration
@@ -144,19 +144,11 @@ public:
bool hasGameDomain(const String &domName) const;
const DomainMap & getGameDomains() const { return _gameDomains; }
-/*
- TODO: Callback/change notification system
- typedef void (*ConfigCallback)(const ConstString &key, void *refCon);
-
- void registerCallback(ConfigCallback cfgc, void *refCon, const ConstString &key = String::emptyString)
- void unregisterCallback(ConfigCallback cfgc, const ConstString &key = String::emptyString)
-*/
-
private:
friend class Singleton<SingletonBaseType>;
ConfigManager();
- void loadFile(const String &filename);
+ void loadFromStream(SeekableReadStream &stream);
void writeDomain(WriteStream &stream, const String &name, const Domain &domain);
Domain _transientDomain;
diff --git a/common/events.h b/common/events.h
index 1a20ee4e9e..645d9e4aed 100644
--- a/common/events.h
+++ b/common/events.h
@@ -27,6 +27,7 @@
#define COMMON_EVENTS_H
#include "common/keyboard.h"
+#include "common/queue.h"
#include "common/rect.h"
#include "common/system.h"
#include "common/noncopyable.h"
@@ -58,6 +59,9 @@ enum EventType {
EVENT_MBUTTONDOWN = 13,
EVENT_MBUTTONUP = 14,
+ EVENT_MAINMENU = 15,
+ EVENT_RTL = 16,
+
EVENT_QUIT = 10,
EVENT_SCREEN_CHANGED = 11,
/**
@@ -178,6 +182,17 @@ public:
*/
virtual int shouldQuit() const = 0;
+ /**
+ * Should we return to the launcher?
+ */
+ virtual int shouldRTL() const = 0;
+
+ /**
+ * Reset the "return to launcher" flag (as returned shouldRTL()) to false.
+ * Used when we have returned to the launcher.
+ */
+ virtual void resetRTL() = 0;
+
// Optional: check whether a given key is currently pressed ????
//virtual bool isKeyPressed(int keycode) = 0;
@@ -187,6 +202,10 @@ public:
// replacing it by a generic getScreenChangeID method here
virtual Common::Keymapper *getKeymapper() = 0;
+
+protected:
+
+ Common::Queue<Common::Event> artificialEventQueue;
};
} // End of namespace Common
diff --git a/common/file.cpp b/common/file.cpp
index 5b465b5e01..cf396a32cd 100644
--- a/common/file.cpp
+++ b/common/file.cpp
@@ -23,254 +23,51 @@
*
*/
+#include "common/archive.h"
#include "common/file.h"
#include "common/fs.h"
-#include "common/hashmap.h"
#include "common/util.h"
-#include "common/hash-str.h"
-#include <errno.h>
-
-#if defined(MACOSX) || defined(IPHONE)
-#include "CoreFoundation/CoreFoundation.h"
-#endif
-
-#ifdef __PLAYSTATION2__
- // for those replaced fopen/fread/etc functions
- typedef unsigned long uint64;
- typedef signed long int64;
- #include "backends/platform/ps2/fileio.h"
-
- #define fopen(a, b) ps2_fopen(a, b)
- #define fclose(a) ps2_fclose(a)
- #define fseek(a, b, c) ps2_fseek(a, b, c)
- #define ftell(a) ps2_ftell(a)
- #define feof(a) ps2_feof(a)
- #define fread(a, b, c, d) ps2_fread(a, b, c, d)
- #define fwrite(a, b, c, d) ps2_fwrite(a, b, c, d)
-
- //#define fprintf ps2_fprintf // used in common/util.cpp
- //#define fflush(a) ps2_fflush(a) // used in common/util.cpp
-
- //#define fgetc(a) ps2_fgetc(a) // not used
- //#define fgets(a, b, c) ps2_fgets(a, b, c) // not used
- //#define fputc(a, b) ps2_fputc(a, b) // not used
- //#define fputs(a, b) ps2_fputs(a, b) // not used
-
- //#define fsize(a) ps2_fsize(a) // not used -- and it is not a standard function either
-#endif
-
-#ifdef __DS__
-
- // These functions replease the standard library functions of the same name.
- // As this header is included after the standard one, I have the chance to #define
- // all of these to my own code.
- //
- // A #define is the only way, as redefinig the functions would cause linker errors.
-
- // These functions need to be #undef'ed, as their original definition
- // in devkitarm is done with #includes (ugh!)
- #undef feof
- #undef clearerr
- //#undef getc
- //#undef ferror
-
- #include "backends/fs/ds/ds-fs.h"
-
-
- //void std_fprintf(FILE* handle, const char* fmt, ...); // used in common/util.cpp
- //void std_fflush(FILE* handle); // used in common/util.cpp
-
- //char* std_fgets(char* str, int size, FILE* file); // not used
- //int std_getc(FILE* handle); // not used
- //char* std_getcwd(char* dir, int dunno); // not used
- //void std_cwd(char* dir); // not used
- //int std_ferror(FILE* handle); // not used
-
- // Only functions used in the ScummVM source have been defined here!
- #define fopen(name, mode) DS::std_fopen(name, mode)
- #define fclose(handle) DS::std_fclose(handle)
- #define fread(ptr, size, items, file) DS::std_fread(ptr, size, items, file)
- #define fwrite(ptr, size, items, file) DS::std_fwrite(ptr, size, items, file)
- #define feof(handle) DS::std_feof(handle)
- #define ftell(handle) DS::std_ftell(handle)
- #define fseek(handle, offset, whence) DS::std_fseek(handle, offset, whence)
- #define clearerr(handle) DS::std_clearerr(handle)
-
- //#define printf(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__)
-
- //#define fprintf(file, fmt, ...) { char str[128]; sprintf(str, fmt, ##__VA_ARGS__); DS::std_fwrite(str, strlen(str), 1, file); }
- //#define fflush(file) DS::std_fflush(file) // used in common/util.cpp
-
- //#define fgets(str, size, file) DS::std_fgets(str, size, file) // not used
- //#define getc(handle) DS::std_getc(handle) // not used
- //#define getcwd(dir, dunno) DS::std_getcwd(dir, dunno) // not used
- #define ferror(handle) DS::std_ferror(handle)
-
-#endif
-
-#ifdef __SYMBIAN32__
- #undef feof
- #undef clearerr
-
- #define FILE void
-
- FILE* symbian_fopen(const char* name, const char* mode);
- void symbian_fclose(FILE* handle);
- size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle);
- size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle);
- bool symbian_feof(FILE* handle);
- long int symbian_ftell(FILE* handle);
- int symbian_fseek(FILE* handle, long int offset, int whence);
- void symbian_clearerr(FILE* handle);
-
- // Only functions used in the ScummVM source have been defined here!
- #define fopen(name, mode) symbian_fopen(name, mode)
- #define fclose(handle) symbian_fclose(handle)
- #define fread(ptr, size, items, file) symbian_fread(ptr, size, items, file)
- #define fwrite(ptr, size, items, file) symbian_fwrite(ptr, size, items, file)
- #define feof(handle) symbian_feof(handle)
- #define ftell(handle) symbian_ftell(handle)
- #define fseek(handle, offset, whence) symbian_fseek(handle, offset, whence)
- #define clearerr(handle) symbian_clearerr(handle)
-#endif
+#include "common/system.h"
namespace Common {
-typedef HashMap<String, int> StringIntMap;
-
-// The following two objects could be turned into static members of class
-// File. However, then we would be forced to #include hashmap in file.h
-// which seems to be a high price just for a simple beautification...
-static StringIntMap *_defaultDirectories;
-static StringMap *_filesMap;
-
-static FILE *fopenNoCase(const String &filename, const String &directory, const char *mode) {
- FILE *file;
- String dirBuf(directory);
- String fileBuf(filename);
-
-#if !defined(__GP32__) && !defined(PALMOS_MODE)
- // Add a trailing slash, if necessary.
- if (!dirBuf.empty()) {
- const char c = dirBuf.lastChar();
- if (c != ':' && c != '/' && c != '\\')
- dirBuf += '/';
- }
-#endif
-
- // Append the filename to the path string
- String pathBuf(dirBuf);
- pathBuf += fileBuf;
-
- //
- // Try to open the file normally
- //
- file = fopen(pathBuf.c_str(), mode);
-
- //
- // Try again, with file name converted to upper case
- //
- if (!file) {
- fileBuf.toUppercase();
- pathBuf = dirBuf + fileBuf;
- file = fopen(pathBuf.c_str(), mode);
- }
-
- //
- // Try again, with file name converted to lower case
- //
- if (!file) {
- fileBuf.toLowercase();
- pathBuf = dirBuf + fileBuf;
- file = fopen(pathBuf.c_str(), mode);
- }
+static Common::SearchSet *s_searchSet = 0;
- //
- // Try again, with file name capitalized
- //
- if (!file) {
- fileBuf.toLowercase();
- fileBuf.setChar(toupper(fileBuf[0]),0);
- pathBuf = dirBuf + fileBuf;
- file = fopen(pathBuf.c_str(), mode);
- }
-
-#ifdef __amigaos4__
- //
- // Work around for possibility that someone uses AmigaOS "newlib" build with SmartFileSystem (blocksize 512 bytes), leading
- // to buffer size being only 512 bytes. "Clib2" sets the buffer size to 8KB, resulting smooth movie playback. This forces the buffer
- // to be enough also when using "newlib" compile on SFS.
- //
- if (file) {
- setvbuf(file, NULL, _IOFBF, 8192);
- }
-#endif
-
- return file;
-}
void File::addDefaultDirectory(const String &directory) {
FilesystemNode dir(directory);
addDefaultDirectoryRecursive(dir, 1);
}
-void File::addDefaultDirectoryRecursive(const String &directory, int level, const String &prefix) {
+void File::addDefaultDirectoryRecursive(const String &directory, int level) {
FilesystemNode dir(directory);
- addDefaultDirectoryRecursive(dir, level, prefix);
+ addDefaultDirectoryRecursive(dir, level);
}
void File::addDefaultDirectory(const FilesystemNode &directory) {
addDefaultDirectoryRecursive(directory, 1);
}
-void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level, const String &prefix) {
- if (level <= 0)
+void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level) {
+ if (level <= 0 || !dir.exists() || !dir.isDirectory())
return;
- FSList fslist;
- if (!dir.getChildren(fslist, FilesystemNode::kListAll)) {
- // Failed listing the contents of this node, so it is either not a
- // directory, or just doesn't exist at all.
- return;
+ if (!s_searchSet) {
+ s_searchSet = new Common::SearchSet();
+ g_system->addSysArchivesToSearchSet(*s_searchSet);
}
- if (!_defaultDirectories)
- _defaultDirectories = new StringIntMap;
-
- // Do not add directories multiple times, unless this time they are added
- // with a bigger depth.
- const String &directory(dir.getPath());
- if (_defaultDirectories->contains(directory) && (*_defaultDirectories)[directory] >= level)
- return;
- (*_defaultDirectories)[directory] = level;
-
- if (!_filesMap)
- _filesMap = new StringMap;
-
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
- if (file->isDirectory()) {
- addDefaultDirectoryRecursive(file->getPath(), level - 1, prefix + file->getName() + "/");
- } else {
- String lfn(prefix);
- lfn += file->getName();
- lfn.toLowercase();
- if (!_filesMap->contains(lfn)) {
- (*_filesMap)[lfn] = file->getPath();
- }
- }
- }
+ Common::ArchivePtr dataArchive(new Common::FSDirectory(dir, level));
+ s_searchSet->add(dir.getPath(), dataArchive, 1);
}
void File::resetDefaultDirectories() {
- delete _defaultDirectories;
- delete _filesMap;
-
- _defaultDirectories = 0;
- _filesMap = 0;
+ delete s_searchSet;
+ s_searchSet = 0;
}
File::File()
- : _handle(0), _ioFailed(false) {
+ : _handle(0) {
}
File::~File() {
@@ -285,51 +82,21 @@ bool File::open(const String &filename) {
_name.clear();
clearIOFailed();
- String fname(filename);
- fname.toLowercase();
-
- if (_filesMap && _filesMap->contains(fname)) {
- fname = (*_filesMap)[fname];
- debug(3, "Opening hashed: %s", fname.c_str());
- _handle = fopen(fname.c_str(), "rb");
- } else if (_filesMap && _filesMap->contains(fname + ".")) {
+ if (s_searchSet && s_searchSet->hasFile(filename)) {
+ debug(3, "Opening hashed: %s", filename.c_str());
+ _handle = s_searchSet->openFile(filename);
+ } else if (s_searchSet && s_searchSet->hasFile(filename + ".")) {
// WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails"
// sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot)
- fname = (*_filesMap)[fname + "."];
- debug(3, "Opening hashed: %s", fname.c_str());
- _handle = fopen(fname.c_str(), "rb");
+ debug(3, "Opening hashed: %s.", filename.c_str());
+ _handle = s_searchSet->openFile(filename);
} else {
-
- if (_defaultDirectories) {
- // Try all default directories
- StringIntMap::const_iterator x(_defaultDirectories->begin());
- for (; _handle == NULL && x != _defaultDirectories->end(); ++x) {
- _handle = fopenNoCase(filename, x->_key, "rb");
- }
- }
-
// Last resort: try the current directory
- if (_handle == NULL)
- _handle = fopenNoCase(filename, "", "rb");
-
- // Last last (really) resort: try looking inside the application bundle on Mac OS X for the lowercase file.
-#if defined(MACOSX) || defined(IPHONE)
- if (!_handle) {
- CFStringRef cfFileName = CFStringCreateWithBytes(NULL, (const UInt8 *)filename.c_str(), filename.size(), kCFStringEncodingASCII, false);
- CFURLRef fileUrl = CFBundleCopyResourceURL(CFBundleGetMainBundle(), cfFileName, NULL, NULL);
- if (fileUrl) {
- UInt8 buf[256];
- if (CFURLGetFileSystemRepresentation(fileUrl, false, (UInt8 *)buf, 256)) {
- _handle = fopen((char *)buf, "rb");
- }
- CFRelease(fileUrl);
- }
- CFRelease(cfFileName);
- }
-#endif
-
+ FilesystemNode file(filename);
+ if (file.exists() && !file.isDirectory())
+ _handle = file.openForReading();
}
-
+
if (_handle == NULL)
debug(2, "File %s not opened", filename.c_str());
else
@@ -341,18 +108,12 @@ bool File::open(const String &filename) {
bool File::open(const FilesystemNode &node) {
if (!node.exists()) {
- warning("File::open: Trying to open a FilesystemNode which does not exist");
+ warning("File::open: FilesystemNode does not exist");
return false;
} else if (node.isDirectory()) {
- warning("File::open: Trying to open a FilesystemNode which is a directory");
- return false;
- } /*else if (!node.isReadable() && mode == kFileReadMode) {
- warning("File::open: Trying to open an unreadable FilesystemNode object for reading");
+ warning("File::open: FilesystemNode is a directory");
return false;
- } else if (!node.isWritable() && mode == kFileWriteMode) {
- warning("File::open: Trying to open an unwritable FilesystemNode object for writing");
- return false;
- }*/
+ }
String filename(node.getName());
@@ -363,7 +124,7 @@ bool File::open(const FilesystemNode &node) {
clearIOFailed();
_name.clear();
- _handle = fopen(node.getPath().c_str(), "rb");
+ _handle = node.openForReading();
if (_handle == NULL)
debug(2, "File %s not found", filename.c_str());
@@ -374,39 +135,24 @@ bool File::open(const FilesystemNode &node) {
}
bool File::exists(const String &filename) {
- // First try to find the file via a FilesystemNode (in case an absolute
- // path was passed). This is only used to filter out directories.
- FilesystemNode file(filename);
- if (file.exists())
- return !file.isDirectory();
-
- // See if the file is already mapped
- if (_filesMap && _filesMap->contains(filename)) {
- FilesystemNode file2((*_filesMap)[filename]);
-
- if (file2.exists())
- return !file2.isDirectory();
- }
-
- // Try all default directories
- if (_defaultDirectories) {
- StringIntMap::const_iterator i(_defaultDirectories->begin());
- for (; i != _defaultDirectories->end(); ++i) {
- FilesystemNode file2(i->_key + filename);
-
- if(file2.exists())
- return !file2.isDirectory();
- }
+ if (s_searchSet && s_searchSet->hasFile(filename)) {
+ return true;
+ } else if (s_searchSet && s_searchSet->hasFile(filename + ".")) {
+ // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails"
+ // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot)
+ return true;
+ } else {
+ // Last resort: try the current directory
+ FilesystemNode file(filename);
+ if (file.exists() && !file.isDirectory())
+ return true;
}
-
- //Try opening the file inside the local directory as a last resort
- File tmp;
- return tmp.open(filename);
+
+ return false;
}
void File::close() {
- if (_handle)
- fclose((FILE *)_handle);
+ delete _handle;
_handle = NULL;
}
@@ -416,59 +162,47 @@ bool File::isOpen() const {
bool File::ioFailed() const {
// TODO/FIXME: Just use ferror() here?
- return _ioFailed != 0;
+ return !_handle || _handle->ioFailed();
}
void File::clearIOFailed() {
- // TODO/FIXME: Just use clearerr() here?
- _ioFailed = false;
+ if (_handle)
+ _handle->clearIOFailed();
}
-bool File::eof() const {
+bool File::err() const {
assert(_handle);
-
- return feof((FILE *)_handle) != 0;
+ return _handle->err();
}
-uint32 File::pos() const {
+void File::clearErr() {
assert(_handle);
-
- return ftell((FILE *)_handle);
+ _handle->clearErr();
}
-uint32 File::size() const {
+bool File::eos() const {
assert(_handle);
+ return _handle->eos();
+}
- uint32 oldPos = ftell((FILE *)_handle);
- fseek((FILE *)_handle, 0, SEEK_END);
- uint32 length = ftell((FILE *)_handle);
- fseek((FILE *)_handle, oldPos, SEEK_SET);
-
- return length;
+int32 File::pos() const {
+ assert(_handle);
+ return _handle->pos();
}
-void File::seek(int32 offs, int whence) {
+int32 File::size() const {
assert(_handle);
+ return _handle->size();
+}
- if (fseek((FILE *)_handle, offs, whence) != 0)
- clearerr((FILE *)_handle);
+bool File::seek(int32 offs, int whence) {
+ assert(_handle);
+ return _handle->seek(offs, whence);
}
uint32 File::read(void *ptr, uint32 len) {
- byte *ptr2 = (byte *)ptr;
- uint32 real_len;
-
assert(_handle);
-
- if (len == 0)
- return 0;
-
- real_len = fread(ptr2, 1, len, (FILE *)_handle);
- if (real_len < len) {
- _ioFailed = true;
- }
-
- return real_len;
+ return _handle->read(ptr, len);
}
@@ -483,20 +217,28 @@ bool DumpFile::open(const String &filename) {
assert(!filename.empty());
assert(!_handle);
- String fname(filename);
- fname.toLowercase();
-
- _handle = fopenNoCase(filename, "", "wb");
+ FilesystemNode node(filename);
+ return open(node);
+}
+
+bool DumpFile::open(const FilesystemNode &node) {
+ assert(!_handle);
+
+ if (node.isDirectory()) {
+ warning("DumpFile::open: FilesystemNode is a directory");
+ return false;
+ }
+
+ _handle = node.openForWriting();
if (_handle == NULL)
- debug(2, "Failed to open '%s' for writing", filename.c_str());
+ debug(2, "File %s not found", node.getName().c_str());
return _handle != NULL;
}
void DumpFile::close() {
- if (_handle)
- fclose((FILE *)_handle);
+ delete _handle;
_handle = NULL;
}
@@ -504,29 +246,24 @@ bool DumpFile::isOpen() const {
return _handle != NULL;
}
-bool DumpFile::ioFailed() const {
+bool DumpFile::err() const {
assert(_handle);
- return ferror((FILE *)_handle) != 0;
+ return _handle->ioFailed();
}
-void DumpFile::clearIOFailed() {
+void DumpFile::clearErr() {
assert(_handle);
- clearerr((FILE *)_handle);
+ _handle->clearIOFailed();
}
-bool DumpFile::eof() const {
+uint32 DumpFile::write(const void *ptr, uint32 len) {
assert(_handle);
- return feof((FILE *)_handle) != 0;
+ return _handle->write(ptr, len);
}
-uint32 DumpFile::write(const void *ptr, uint32 len) {
+bool DumpFile::flush() {
assert(_handle);
-
- if (len == 0)
- return 0;
-
- return (uint32)fwrite(ptr, 1, len, (FILE *)_handle);
+ return _handle->flush();
}
-
} // End of namespace Common
diff --git a/common/file.h b/common/file.h
index 3c2520b07c..a2739f795f 100644
--- a/common/file.h
+++ b/common/file.h
@@ -31,20 +31,17 @@
#include "common/str.h"
#include "common/stream.h"
-class FilesystemNode;
-
namespace Common {
+class FilesystemNode;
+
/**
* TODO: vital to document this core class properly!!! For both users and implementors
*/
class File : public SeekableReadStream, public NonCopyable {
protected:
/** File handle to the actual file; 0 if no file is open. */
- void *_handle;
-
- /** Status flag which tells about recent I/O failures. */
- bool _ioFailed;
+ SeekableReadStream *_handle;
/** The name of this file, for debugging. */
String _name;
@@ -52,10 +49,10 @@ protected:
public:
static void addDefaultDirectory(const String &directory);
- static void addDefaultDirectoryRecursive(const String &directory, int level = 4, const String &prefix = "");
+ static void addDefaultDirectoryRecursive(const String &directory, int level = 4);
static void addDefaultDirectory(const FilesystemNode &directory);
- static void addDefaultDirectoryRecursive(const FilesystemNode &directory, int level = 4, const String &prefix = "");
+ static void addDefaultDirectoryRecursive(const FilesystemNode &directory, int level = 4);
static void resetDefaultDirectories();
@@ -93,18 +90,13 @@ public:
bool ioFailed() const;
void clearIOFailed();
- bool eos() const { return eof(); }
-
- /**
- * Checks for end of file.
- *
- * @return: true if the end of file is reached, false otherwise.
- */
- virtual bool eof() const;
+ bool err() const;
+ void clearErr();
+ bool eos() const;
- virtual uint32 pos() const;
- virtual uint32 size() const;
- void seek(int32 offs, int whence = SEEK_SET);
+ virtual int32 pos() const;
+ virtual int32 size() const;
+ bool seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *dataPtr, uint32 dataSize);
};
@@ -118,14 +110,14 @@ public:
class DumpFile : public WriteStream, public NonCopyable {
protected:
/** File handle to the actual file; 0 if no file is open. */
- void *_handle;
+ WriteStream *_handle;
public:
DumpFile();
virtual ~DumpFile();
virtual bool open(const String &filename);
- //virtual bool open(const FilesystemNode &node);
+ virtual bool open(const FilesystemNode &node);
virtual void close();
@@ -136,22 +128,14 @@ public:
*/
bool isOpen() const;
+ bool err() const;
+ void clearErr();
- bool ioFailed() const;
- void clearIOFailed();
- bool eos() const { return eof(); }
-
- /**
- * Checks for end of file.
- *
- * @return: true if the end of file is reached, false otherwise.
- */
- virtual bool eof() const;
+ virtual uint32 write(const void *dataPtr, uint32 dataSize);
- uint32 write(const void *dataPtr, uint32 dataSize);
+ virtual bool flush();
};
-
} // End of namespace Common
#endif
diff --git a/common/fs.cpp b/common/fs.cpp
index 7d803dacd4..4d31ac09fa 100644
--- a/common/fs.cpp
+++ b/common/fs.cpp
@@ -27,6 +27,8 @@
#include "backends/fs/abstract-fs.h"
#include "backends/fs/fs-factory.h"
+namespace Common {
+
FilesystemNode::FilesystemNode() {
}
@@ -49,7 +51,7 @@ bool FilesystemNode::operator<(const FilesystemNode& node) const {
if (isDirectory() != node.isDirectory())
return isDirectory();
- return scumm_stricmp(getDisplayName().c_str(), node.getDisplayName().c_str()) < 0;
+ return getDisplayName().compareToIgnoreCase(node.getDisplayName()) < 0;
}
bool FilesystemNode::exists() const {
@@ -60,10 +62,10 @@ bool FilesystemNode::exists() const {
}
FilesystemNode FilesystemNode::getChild(const Common::String &n) const {
- if (_realNode == 0)
- return *this;
+ // If this node is invalid or not a directory, return an invalid node
+ if (_realNode == 0 || !_realNode->isDirectory())
+ return FilesystemNode();
- assert(_realNode->isDirectory());
AbstractFilesystemNode *node = _realNode->getChild(n);
return FilesystemNode(node);
}
@@ -152,7 +154,7 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h
} else {
Common::String filename = entry->getName();
filename.toUppercase();
- if (Common::matchString(filename.c_str(), pattern.c_str())) {
+ if (filename.matchString(pattern)) {
results.push_back(*entry);
if (!exhaustive)
@@ -170,3 +172,32 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h
return !results.empty();
}
+
+Common::SeekableReadStream *FilesystemNode::openForReading() const {
+ if (_realNode == 0)
+ return 0;
+
+ if (!_realNode->exists()) {
+ warning("FilesystemNode::openForReading: FilesystemNode does not exist");
+ return false;
+ } else if (_realNode->isDirectory()) {
+ warning("FilesystemNode::openForReading: FilesystemNode is a directory");
+ return false;
+ }
+
+ return _realNode->openForReading();
+}
+
+Common::WriteStream *FilesystemNode::openForWriting() const {
+ if (_realNode == 0)
+ return 0;
+
+ if (_realNode->isDirectory()) {
+ warning("FilesystemNode::openForWriting: FilesystemNode is a directory");
+ return 0;
+ }
+
+ return _realNode->openForWriting();
+}
+
+} // End of namespace Common
diff --git a/common/fs.h b/common/fs.h
index ed7355cc00..c5f7ca6b4c 100644
--- a/common/fs.h
+++ b/common/fs.h
@@ -29,10 +29,13 @@
#include "common/ptr.h"
#include "common/str.h"
-//namespace Common {
+class AbstractFilesystemNode;
+
+namespace Common {
class FilesystemNode;
-class AbstractFilesystemNode;
+class SeekableReadStream;
+class WriteStream;
/**
* List of multiple file system nodes. E.g. the contents of a given directory.
@@ -49,22 +52,6 @@ class FSList : public Common::Array<FilesystemNode> {};
* To this end, we abstract away from paths; implementations can be based on
* paths (and it's left to them whether / or \ or : is the path separator :-);
* but it is also possible to use inodes or vrefs (MacOS 9) or anything else.
- *
- * NOTE: Backends still have to provide a way to extract a path from a FSIntern
- *
- * You may ask now: "isn't this cheating? Why do we go through all this when we use
- * a path in the end anyway?!?".
- * Well, for once as long as we don't provide our own file open/read/write API, we
- * still have to use fopen(). Since all our targets already support fopen(), it should
- * be possible to get a fopen() compatible string for any file system node.
- *
- * Secondly, with this abstraction layer, we still avoid a lot of complications based on
- * differences in FS roots, different path separators, or even systems with no real
- * paths (MacOS 9 doesn't even have the notion of a "current directory").
- * And if we ever want to support devices with no FS in the classical sense (Palm...),
- * we can build upon this.
- *
- * This class acts as a wrapper around the AbstractFilesystemNode class defined in backends/fs.
*/
class FilesystemNode {
private:
@@ -108,24 +95,36 @@ public:
bool operator<(const FilesystemNode& node) const;
/**
- * Indicates whether the object referred by this path exists in the filesystem or not.
+ * Indicates whether the object referred by this node exists in the filesystem or not.
*
- * @return bool true if the path exists, false otherwise.
+ * @return bool true if the node exists, false otherwise.
*/
virtual bool exists() const;
/**
- * Fetch a child node of this node, with the given name. Only valid for
- * directory nodes (an assertion is triggered otherwise).
- * If no child node with the given name exists, an invalid node is returned.
+ * Create a new node referring to a child node of the current node, which
+ * must be a directory node (otherwise an invalid node is returned).
+ * If a child matching the name exists, a normal node for it is returned.
+ * If no child with the name exists, a node for it is still returned,
+ * but exists() will return 'false' for it. This node can however be used
+ * to create a new file using the openForWriting() method.
+ *
+ * @todo If openForWriting() (or a hypothetical future mkdir() method) is used,
+ * this should affect what exists/isDirectory/isReadable/isWritable return
+ * for existing nodes. However, this is not the case for many existing
+ * FSNode implementations. Either fix those, or document that FSNodes
+ * can become 'stale'...
+ *
+ * @param name the name of a child of this directory
+ * @return the node referring to the child with the given name
*/
FilesystemNode getChild(const Common::String &name) const;
/**
- * Return a list of child nodes of this directory node. If called on a node
+ * Return a list of all child nodes of this directory node. If called on a node
* that does not represent a directory, false is returned.
*
- * @return true if succesful, false otherwise (e.g. when the directory does not exist).
+ * @return true if successful, false otherwise (e.g. when the directory does not exist).
*/
virtual bool getChildren(FSList &fslist, ListMode mode = kListDirectoriesOnly, bool hidden = false) const;
@@ -149,10 +148,11 @@ public:
virtual Common::String getName() const;
/**
- * Return a string representation of the file which can be passed to fopen(),
- * and is suitable for archiving (i.e. writing to the config file).
- * This will usually be a 'path' (hence the name of the method), but can
- * be anything that fulfills the above criterions.
+ * Return a string representation of the file which is suitable for
+ * archiving (i.e. writing to the config file). This will usually be a
+ * 'path' (hence the name of the method), but can be anything that meets
+ * the above criterions. What a 'path' is differs greatly from system to
+ * system anyway.
*
* @note Do not assume that this string contains (back)slashes or any
* other kind of 'path separators'.
@@ -168,7 +168,7 @@ public:
FilesystemNode getParent() const;
/**
- * Indicates whether the path refers to a directory or not.
+ * Indicates whether the node refers to a directory or not.
*
* @todo Currently we assume that a node that is not a directory
* automatically is a file (ignoring things like symlinks or pipes).
@@ -179,28 +179,28 @@ public:
virtual bool isDirectory() const;
/**
- * Indicates whether the object referred by this path can be read from or not.
+ * Indicates whether the object referred by this node can be read from or not.
*
- * If the path refers to a directory, readability implies being able to read
+ * If the node refers to a directory, readability implies being able to read
* and list the directory entries.
*
- * If the path refers to a file, readability implies being able to read the
+ * If the node refers to a file, readability implies being able to read the
* contents of the file.
*
- * @return bool true if the object can be read, false otherwise.
+ * @return true if the object can be read, false otherwise.
*/
virtual bool isReadable() const;
/**
- * Indicates whether the object referred by this path can be written to or not.
+ * Indicates whether the object referred by this node can be written to or not.
*
- * If the path refers to a directory, writability implies being able to modify
+ * If the node refers to a directory, writability implies being able to modify
* the directory entry (i.e. rename the directory, remove it or write files inside of it).
*
- * If the path refers to a file, writability implies being able to write data
+ * If the node refers to a file, writability implies being able to write data
* to the file.
*
- * @return bool true if the object can be written to, false otherwise.
+ * @return true if the object can be written to, false otherwise.
*/
virtual bool isWritable() const;
@@ -221,8 +221,27 @@ public:
* @return true if matches could be found, false otherwise.
*/
virtual bool lookupFile(FSList &results, const Common::String &pattern, bool hidden, bool exhaustive, int depth = -1) const;
+
+
+ /**
+ * Creates a SeekableReadStream instance corresponding to the file
+ * referred by this node. This assumes that the node actually refers
+ * to a readable file. If this is not the case, 0 is returned.
+ *
+ * @return pointer to the stream object, 0 in case of a failure
+ */
+ virtual Common::SeekableReadStream *openForReading() const;
+
+ /**
+ * Creates a WriteStream instance corresponding to the file
+ * referred by this node. This assumes that the node actually refers
+ * to a readable file. If this is not the case, 0 is returned.
+ *
+ * @return pointer to the stream object, 0 in case of a failure
+ */
+ virtual Common::WriteStream *openForWriting() const;
};
-//} // End of namespace Common
+} // End of namespace Common
#endif //COMMON_FS_H
diff --git a/common/func.h b/common/func.h
index 1c045b9e5d..6aa5b76ed4 100644
--- a/common/func.h
+++ b/common/func.h
@@ -78,7 +78,7 @@ private:
Op _op;
typename Op::FirstArgumentType _arg1;
public:
- Binder1st(const Op &op, const typename Op::FirstArgumentType &arg1) : _op(op), _arg1(arg1) {}
+ Binder1st(const Op &op, typename Op::FirstArgumentType arg1) : _op(op), _arg1(arg1) {}
typename Op::ResultType operator()(typename Op::SecondArgumentType v) const {
return _op(_arg1, v);
@@ -89,8 +89,8 @@ public:
* Transforms a binary function object into an unary function object.
* To achieve that the first parameter is bound to the passed value t.
*/
-template<class Op, class T>
-inline Binder1st<Op> bind1st(const Op &op, const T &t) {
+template<class Op>
+inline Binder1st<Op> bind1st(const Op &op, typename Op::FirstArgumentType t) {
return Binder1st<Op>(op, t);
}
@@ -100,7 +100,7 @@ private:
Op _op;
typename Op::SecondArgumentType _arg2;
public:
- Binder2nd(const Op &op, const typename Op::SecondArgumentType &arg2) : _op(op), _arg2(arg2) {}
+ Binder2nd(const Op &op, typename Op::SecondArgumentType arg2) : _op(op), _arg2(arg2) {}
typename Op::ResultType operator()(typename Op::FirstArgumentType v) const {
return _op(v, _arg2);
@@ -109,10 +109,10 @@ public:
/**
* Transforms a binary function object into an unary function object.
- * To achieve that the second parameter is bound to the passed value t.
+ * To achieve that the first parameter is bound to the passed value t.
*/
-template<class Op, class T>
-inline Binder2nd<Op> bind2nd(const Op &op, const T &t) {
+template<class Op>
+inline Binder2nd<Op> bind2nd(const Op &op, typename Op::SecondArgumentType t) {
return Binder2nd<Op>(op, t);
}
@@ -159,7 +159,7 @@ inline PointerToBinaryFunc<Arg1, Arg2, Result> ptr_fun(Result (*func)(Arg1, Arg2
}
template<class Result, class T>
-class MemFunc0 : public UnaryFunction<T*, Result> {
+class MemFunc0 : public UnaryFunction<T *, Result> {
private:
Result (T::*_func)();
public:
@@ -179,7 +179,7 @@ public:
typedef Result (T::*FuncType)() const;
ConstMemFunc0(const FuncType &func) : _func(func) {}
- Result operator()(T *v) const {
+ Result operator()(const T *v) const {
return (v->*_func)();
}
};
@@ -205,7 +205,7 @@ public:
typedef Result (T::*FuncType)(Arg) const;
ConstMemFunc1(const FuncType &func) : _func(func) {}
- Result operator()(T *v1, Arg v2) const {
+ Result operator()(const T *v1, Arg v2) const {
return (v1->*_func)(v2);
}
};
@@ -252,6 +252,105 @@ inline ConstMemFunc1<Result, Arg, T> mem_fun(Result (T::*f)(Arg) const) {
return ConstMemFunc1<Result, Arg, T>(f);
}
+template<class Result, class T>
+class MemFuncRef0 : public UnaryFunction<T &, Result> {
+private:
+ Result (T::*_func)();
+public:
+ typedef Result (T::*FuncType)();
+
+ MemFuncRef0(const FuncType &func) : _func(func) {}
+ Result operator()(T &v) const {
+ return (v.*_func)();
+ }
+};
+
+template<class Result, class T>
+class ConstMemFuncRef0 : public UnaryFunction<T &, Result> {
+private:
+ Result (T::*_func)() const;
+public:
+ typedef Result (T::*FuncType)() const;
+
+ ConstMemFuncRef0(const FuncType &func) : _func(func) {}
+ Result operator()(const T &v) const {
+ return (v.*_func)();
+ }
+};
+
+template<class Result, class Arg, class T>
+class MemFuncRef1 : public BinaryFunction<T &, Arg, Result> {
+private:
+ Result (T::*_func)(Arg);
+public:
+ typedef Result (T::*FuncType)(Arg);
+
+ MemFuncRef1(const FuncType &func) : _func(func) {}
+ Result operator()(T &v1, Arg v2) const {
+ return (v1.*_func)(v2);
+ }
+};
+
+template<class Result, class Arg, class T>
+class ConstMemFuncRef1 : public BinaryFunction<T &, Arg, Result> {
+private:
+ Result (T::*_func)(Arg) const;
+public:
+ typedef Result (T::*FuncType)(Arg) const;
+
+ ConstMemFuncRef1(const FuncType &func) : _func(func) {}
+ Result operator()(const T &v1, Arg v2) const {
+ return (v1.*_func)(v2);
+ }
+};
+
+/**
+ * Creates a unary function object from a class member function pointer.
+ * The parameter passed to the function object is the object instance to
+ * be used for the function call. Note unlike mem_fun, it takes a reference
+ * as parameter. Note unlike mem_fun, it takes a reference
+ * as parameter.
+ */
+template<class Result, class T>
+inline MemFuncRef0<Result, T> mem_fun_ref(Result (T::*f)()) {
+ return MemFuncRef0<Result, T>(f);
+}
+
+/**
+ * Creates a unary function object from a class member function pointer.
+ * The parameter passed to the function object is the object instance to
+ * be used for the function call. Note unlike mem_fun, it takes a reference
+ * as parameter.
+ */
+template<class Result, class T>
+inline ConstMemFuncRef0<Result, T> mem_fun_Ref(Result (T::*f)() const) {
+ return ConstMemFuncRef0<Result, T>(f);
+}
+
+/**
+ * Creates a binary function object from a class member function pointer.
+ * The first parameter passed to the function object is the object instance to
+ * be used for the function call. Note unlike mem_fun, it takes a reference
+ * as parameter.
+ * The second one is the parameter passed to the member function.
+ */
+template<class Result, class Arg, class T>
+inline MemFuncRef1<Result, Arg, T> mem_fun_ref(Result (T::*f)(Arg)) {
+ return MemFuncRef1<Result, Arg, T>(f);
+}
+
+/**
+ * Creates a binary function object from a class member function pointer.
+ * The first parameter passed to the function object is the object instance to
+ * be used for the function call. Note unlike mem_fun, it takes a reference
+ * as parameter.
+ * The second one is the parameter passed to the member function.
+ */
+template<class Result, class Arg, class T>
+inline ConstMemFuncRef1<Result, Arg, T> mem_fun_ref(Result (T::*f)(Arg) const) {
+ return ConstMemFuncRef1<Result, Arg, T>(f);
+}
+
// functor code
/**
diff --git a/common/hash-str.h b/common/hash-str.h
index f64b62daed..40557037e7 100644
--- a/common/hash-str.h
+++ b/common/hash-str.h
@@ -39,7 +39,7 @@ inline uint hashit_lower(const String &str) { return hashit_lower(str.c_str());
// FIXME: The following functors obviously are not consistently named
struct CaseSensitiveString_EqualTo {
- bool operator()(const String& x, const String& y) const { return strcmp(x.c_str(), y.c_str()) == 0; }
+ bool operator()(const String& x, const String& y) const { return x.equals(y); }
};
struct CaseSensitiveString_Hash {
@@ -48,7 +48,7 @@ struct CaseSensitiveString_Hash {
struct IgnoreCase_EqualTo {
- bool operator()(const String& x, const String& y) const { return scumm_stricmp(x.c_str(), y.c_str()) == 0; }
+ bool operator()(const String& x, const String& y) const { return x.equalsIgnoreCase(y); }
};
struct IgnoreCase_Hash {
diff --git a/common/hashmap.cpp b/common/hashmap.cpp
index 4749234740..b8f2608901 100644
--- a/common/hashmap.cpp
+++ b/common/hashmap.cpp
@@ -24,70 +24,86 @@
*/
// The hash map (associative array) implementation in this file is
-// based on code by Andrew Y. Ng, 1996:
-
-/*
- * Copyright (c) 1998-2003 Massachusetts Institute of Technology.
- * This code was developed as part of the Haystack research project
- * (http://haystack.lcs.mit.edu/). Permission is hereby granted,
- * free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
+// based on the PyDict implementation of CPython. The erase() method
+// is based on example code in the Wikipedia article on Hash tables.
#include "common/hashmap.h"
namespace Common {
-// const char *:
+// Hash function for strings, taken from CPython.
uint hashit(const char *p) {
- uint hash = 0;
+ uint hash = *p << 7;
byte c;
- while ((c = *p++))
- hash = (hash * 31 + c);
- return hash;
+ int size = 0;
+ while ((c = *p++)) {
+ hash = (1000003 * hash) ^ c;
+ size++;
+ }
+ return hash ^ size;
}
+// Like hashit, but converts every char to lowercase before hashing.
uint hashit_lower(const char *p) {
- uint hash = 0;
+ uint hash = tolower(*p) << 7;
byte c;
- while ((c = *p++))
- hash = (hash * 31 + tolower(c));
- return hash;
+ int size = 0;
+ while ((c = *p++)) {
+ hash = (1000003 * hash) ^ tolower(c);
+ size++;
+ }
+ return hash ^ size;
}
-// The following table is taken from the GNU ISO C++ Library's hashtable.h file.
-static const uint primes[] = {
- 53ul, 97ul, 193ul, 389ul, 769ul,
- 1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
- 49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
- 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
- 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
- 1610612741ul, 3221225473ul, 4294967291ul
-};
+#ifdef DEBUG_HASH_COLLISIONS
+static double
+ g_collisions = 0,
+ g_lookups = 0,
+ g_collPerLook = 0,
+ g_capacity = 0,
+ g_size = 0;
+static int g_max_capacity = 0, g_max_size = 0;
+static int g_totalHashmaps = 0;
+static int g_stats[4] = {0,0,0,0};
-uint nextTableSize(uint x) {
- int i = 0;
- while (x >= primes[i])
- i++;
- return primes[i];
-}
+void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele) {
+ g_collisions += collisions;
+ g_lookups += lookups;
+ if (lookups)
+ g_collPerLook += (double)collisions / (double)lookups;
+ g_capacity += arrsize;
+ g_size += nele;
+ g_totalHashmaps++;
+
+ if (3*nele <= 2*8)
+ g_stats[0]++;
+ if (3*nele <= 2*16)
+ g_stats[1]++;
+ if (3*nele <= 2*32)
+ g_stats[2]++;
+ if (3*nele <= 2*64)
+ g_stats[3]++;
+
+ g_max_capacity = MAX(g_max_capacity, arrsize);
+ g_max_size = MAX(g_max_size, nele);
+ fprintf(stdout, "%d hashmaps: colls %.1f; lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
+ g_totalHashmaps,
+ g_collisions / g_totalHashmaps,
+ g_lookups / g_totalHashmaps,
+ 100 * g_collPerLook / g_totalHashmaps,
+ g_size / g_totalHashmaps, g_max_size,
+ g_capacity / g_totalHashmaps, g_max_capacity);
+ fprintf(stdout, " %d less than %d; %d less than %d; %d less than %d; %d less than %d\n",
+ g_stats[0], 2*8/3,
+ g_stats[1],2*16/3,
+ g_stats[2],2*32/3,
+ g_stats[3],2*64/3);
+
+ // TODO:
+ // * Should record the maximal size of the map during its lifetime, not that at its death
+ // * Should do some statistics: how many maps are less than 2/3*8, 2/3*16, 2/3*32, ...
+}
+#endif
} // End of namespace Common
diff --git a/common/hashmap.h b/common/hashmap.h
index ab6e737d74..81f5ee84b4 100644
--- a/common/hashmap.h
+++ b/common/hashmap.h
@@ -24,32 +24,8 @@
*/
// The hash map (associative array) implementation in this file is
-// based on code by Andrew Y. Ng, 1996:
-
-/*
- * Copyright (c) 1998-2003 Massachusetts Institute of Technology.
- * This code was developed as part of the Haystack research project
- * (http://haystack.lcs.mit.edu/). Permission is hereby granted,
- * free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
+// based on the PyDict implementation of CPython. The erase() method
+// is based on example code in the Wikipedia article on Hash tables.
#ifndef COMMON_HASHMAP_H
#define COMMON_HASHMAP_H
@@ -58,29 +34,22 @@
#include "common/str.h"
#include "common/util.h"
-// FIXME: Since this define is very system dependant,
-// it should be moved to the appropriate H file instead.
-// Portdefs might be a good location for example
-#if !defined(__SYMBIAN32__)
#define USE_HASHMAP_MEMORY_POOL
-#endif
-
#ifdef USE_HASHMAP_MEMORY_POOL
#include "common/memorypool.h"
// FIXME: we sadly can't assume standard C++ to be present
// on every system we support, so we should get rid of this.
// The solution should be to write a simple placement new
// on our own.
+
+// Symbian does not have <new> but the new operator
+#if !defined(__SYMBIAN32__)
#include <new>
#endif
+#endif
namespace Common {
-// The table sizes ideally are primes. We use a helper function to find
-// suitable table sizes.
-uint nextTableSize(uint x);
-
-
// Enable the following #define if you want to check how many collisions the
// code produces (many collisions indicate either a bad hash function, or a
// hash table that is too small).
@@ -115,9 +84,24 @@ public:
Node(const Key &key) : _key(key), _value() {}
};
+ enum {
+ HASHMAP_PERTURB_SHIFT = 5,
+ HASHMAP_MIN_CAPACITY = 16,
+
+ // The quotient of the next two constants controls how much the
+ // internal storage of the hashmap may fill up before being
+ // increased automatically.
+ // Note: the quotient of these two must be between and different
+ // from 0 and 1.
+ HASHMAP_LOADFACTOR_NUMERATOR = 2,
+ HASHMAP_LOADFACTOR_DENOMINATOR = 3,
+
+ HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
+ };
+
#ifdef USE_HASHMAP_MEMORY_POOL
- MemoryPool _nodePool;
+ FixedSizeMemoryPool<sizeof(Node), HASHMAP_MEMORYPOOL_SIZE> _nodePool;
Node *allocNode(const Key &key) {
void* mem = _nodePool.malloc();
@@ -138,8 +122,9 @@ public:
}
#endif
- Node **_arr; // hashtable of size arrsize.
- uint _arrsize, _nele;
+ Node **_storage; // hashtable of size arrsize.
+ uint _mask; /**< Capacity of the HashMap minus one; must be a power of two of minus one */
+ uint _size;
HashFunc _hash;
EqualFunc _equal;
@@ -154,7 +139,7 @@ public:
void assign(const HM_t &map);
int lookup(const Key &key) const;
int lookupAndCreateIfMissing(const Key &key);
- void expand_array(uint newsize);
+ void expandStorage(uint newCapacity);
template<class T> friend class IteratorImpl;
@@ -176,8 +161,8 @@ public:
NodeType *deref() const {
assert(_hashmap != 0);
- assert(_idx < _hashmap->_arrsize);
- Node *node = _hashmap->_arr[_idx];
+ assert(_idx <= _hashmap->_mask);
+ Node *node = _hashmap->_storage[_idx];
assert(node != 0);
return node;
}
@@ -197,8 +182,8 @@ public:
assert(_hashmap);
do {
_idx++;
- } while (_idx < _hashmap->_arrsize && _hashmap->_arr[_idx] == 0);
- if (_idx >= _hashmap->_arrsize)
+ } while (_idx <= _hashmap->_mask && _hashmap->_storage[_idx] == 0);
+ if (_idx > _hashmap->_mask)
_idx = (uint)-1;
return *this;
@@ -225,7 +210,7 @@ public:
// Remove the previous content and ...
clear();
- delete[] _arr;
+ delete[] _storage;
// ... copy the new stuff.
assign(map);
return *this;
@@ -244,12 +229,12 @@ public:
void erase(const Key &key);
- uint size() const { return _nele; }
+ uint size() const { return _size; }
iterator begin() {
// Find and return the _key non-empty entry
- for (uint ctr = 0; ctr < _arrsize; ++ctr) {
- if (_arr[ctr])
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (_storage[ctr])
return iterator(ctr, this);
}
return end();
@@ -260,8 +245,8 @@ public:
const_iterator begin() const {
// Find and return the first non-empty entry
- for (uint ctr = 0; ctr < _arrsize; ++ctr) {
- if (_arr[ctr])
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (_storage[ctr])
return const_iterator(ctr, this);
}
return end();
@@ -272,14 +257,14 @@ public:
iterator find(const Key &key) {
uint ctr = lookup(key);
- if (_arr[ctr])
+ if (_storage[ctr])
return iterator(ctr, this);
return end();
}
const_iterator find(const Key &key) const {
uint ctr = lookup(key);
- if (_arr[ctr])
+ if (_storage[ctr])
return const_iterator(ctr, this);
return end();
}
@@ -287,7 +272,7 @@ public:
// TODO: insert() method?
bool empty() const {
- return (_nele == 0);
+ return (_size == 0);
}
};
@@ -299,16 +284,13 @@ public:
*/
template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() :
-#ifdef USE_HASHMAP_MEMORY_POOL
- _nodePool(sizeof(Node)),
-#endif
_defaultVal() {
- _arrsize = nextTableSize(0);
- _arr = new Node *[_arrsize];
- assert(_arr != NULL);
- memset(_arr, 0, _arrsize * sizeof(Node *));
+ _mask = HASHMAP_MIN_CAPACITY - 1;
+ _storage = new Node *[HASHMAP_MIN_CAPACITY];
+ assert(_storage != NULL);
+ memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *));
- _nele = 0;
+ _size = 0;
#ifdef DEBUG_HASH_COLLISIONS
_collisions = 0;
@@ -323,9 +305,6 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() :
*/
template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
-#ifdef USE_HASHMAP_MEMORY_POOL
- _nodePool(sizeof(Node)),
-#endif
_defaultVal() {
assign(map);
}
@@ -335,11 +314,15 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
*/
template<class Key, class Val, class HashFunc, class EqualFunc>
HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
- for (uint ctr = 0; ctr < _arrsize; ++ctr)
- if (_arr[ctr] != NULL)
- freeNode(_arr[ctr]);
+ for (uint ctr = 0; ctr <= _mask; ++ctr)
+ if (_storage[ctr] != NULL)
+ freeNode(_storage[ctr]);
- delete[] _arr;
+ delete[] _storage;
+#ifdef DEBUG_HASH_COLLISIONS
+ extern void updateHashCollisionStats(int, int, int, int);
+ updateHashCollisionStats(_collisions, _lookups, _mask+1, _size);
+#endif
}
/**
@@ -351,95 +334,102 @@ HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
*/
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
- _arrsize = map._arrsize;
- _arr = new Node *[_arrsize];
- assert(_arr != NULL);
- memset(_arr, 0, _arrsize * sizeof(Node *));
+ _mask = map._mask;
+ _storage = new Node *[_mask+1];
+ assert(_storage != NULL);
+ memset(_storage, 0, (_mask+1) * sizeof(Node *));
// Simply clone the map given to us, one by one.
- _nele = 0;
- for (uint ctr = 0; ctr < _arrsize; ++ctr) {
- if (map._arr[ctr] != NULL) {
- _arr[ctr] = allocNode(map._arr[ctr]->_key);
- _arr[ctr]->_value = map._arr[ctr]->_value;
- _nele++;
+ _size = 0;
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (map._storage[ctr] != NULL) {
+ _storage[ctr] = allocNode(map._storage[ctr]->_key);
+ _storage[ctr]->_value = map._storage[ctr]->_value;
+ _size++;
}
}
// Perform a sanity check (to help track down hashmap corruption)
- assert(_nele == map._nele);
+ assert(_size == map._size);
}
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
- for (uint ctr = 0; ctr < _arrsize; ++ctr) {
- if (_arr[ctr] != NULL) {
- freeNode(_arr[ctr]);
- _arr[ctr] = NULL;
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (_storage[ctr] != NULL) {
+ freeNode(_storage[ctr]);
+ _storage[ctr] = NULL;
}
}
- if (shrinkArray && _arrsize > nextTableSize(0)) {
- delete[] _arr;
+#ifdef USE_HASHMAP_MEMORY_POOL
+ _nodePool.freeUnusedPages();
+#endif
+
+ if (shrinkArray && _mask >= HASHMAP_MIN_CAPACITY) {
+ delete[] _storage;
- _arrsize = nextTableSize(0);
- _arr = new Node *[_arrsize];
- assert(_arr != NULL);
- memset(_arr, 0, _arrsize * sizeof(Node *));
+ _mask = HASHMAP_MIN_CAPACITY;
+ _storage = new Node *[HASHMAP_MIN_CAPACITY];
+ assert(_storage != NULL);
+ memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *));
}
- _nele = 0;
+ _size = 0;
}
template<class Key, class Val, class HashFunc, class EqualFunc>
-void HashMap<Key, Val, HashFunc, EqualFunc>::expand_array(uint newsize) {
- assert(newsize > _arrsize);
- uint ctr, dex;
+void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
+ assert(newCapacity > _mask+1);
- const uint old_nele = _nele;
- const uint old_arrsize = _arrsize;
- Node **old_arr = _arr;
+ const uint old_size = _size;
+ const uint old_mask = _mask;
+ Node **old_storage = _storage;
// allocate a new array
- _nele = 0;
- _arrsize = newsize;
- _arr = new Node *[_arrsize];
- assert(_arr != NULL);
- memset(_arr, 0, _arrsize * sizeof(Node *));
+ _size = 0;
+ _mask = newCapacity - 1;
+ _storage = new Node *[newCapacity];
+ assert(_storage != NULL);
+ memset(_storage, 0, newCapacity * sizeof(Node *));
// rehash all the old elements
- for (ctr = 0; ctr < old_arrsize; ++ctr) {
- if (old_arr[ctr] == NULL)
+ for (uint ctr = 0; ctr <= old_mask; ++ctr) {
+ if (old_storage[ctr] == NULL)
continue;
// Insert the element from the old table into the new table.
// Since we know that no key exists twice in the old table, we
// can do this slightly better than by calling lookup, since we
// don't have to call _equal().
- dex = _hash(old_arr[ctr]->_key) % _arrsize;
- while (_arr[dex] != NULL) {
- dex = (dex + 1) % _arrsize;
+ const uint hash = _hash(old_storage[ctr]->_key);
+ uint idx = hash & _mask;
+ for (uint perturb = hash; _storage[idx] != NULL; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ idx = (5 * idx + perturb + 1) & _mask;
}
- _arr[dex] = old_arr[ctr];
- _nele++;
+ _storage[idx] = old_storage[ctr];
+ _size++;
}
// Perform a sanity check: Old number of elements should match the new one!
// This check will fail if some previous operation corrupted this hashmap.
- assert(_nele == old_nele);
+ assert(_size == old_size);
- delete[] old_arr;
+ delete[] old_storage;
return;
}
template<class Key, class Val, class HashFunc, class EqualFunc>
int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
- uint ctr = _hash(key) % _arrsize;
+ const uint hash = _hash(key);
+ uint ctr = hash & _mask;
+ for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ if (_storage[ctr] == NULL || _equal(_storage[ctr]->_key, key))
+ break;
- while (_arr[ctr] != NULL && !_equal(_arr[ctr]->_key, key)) {
- ctr = (ctr + 1) % _arrsize;
+ ctr = (5 * ctr + perturb + 1) & _mask;
#ifdef DEBUG_HASH_COLLISIONS
_collisions++;
@@ -450,7 +440,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
_lookups++;
fprintf(stderr, "collisions %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
_collisions, _lookups, ((double) _collisions / (double)_lookups),
- (const void *)this, _arrsize, _nele);
+ (const void *)this, _mask+1, _size);
#endif
return ctr;
@@ -460,13 +450,15 @@ template<class Key, class Val, class HashFunc, class EqualFunc>
int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) {
uint ctr = lookup(key);
- if (_arr[ctr] == NULL) {
- _arr[ctr] = allocNode(key);
- _nele++;
+ if (_storage[ctr] == NULL) {
+ _storage[ctr] = allocNode(key);
+ _size++;
- // Keep the load factor below 75%.
- if (_nele > _arrsize * 75 / 100) {
- expand_array(nextTableSize(_arrsize));
+ // Keep the load factor below a certain threshold.
+ uint capacity = _mask + 1;
+ if (_size * HASHMAP_LOADFACTOR_DENOMINATOR > capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
+ capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
+ expandStorage(capacity);
ctr = lookup(key);
}
}
@@ -478,7 +470,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &
template<class Key, class Val, class HashFunc, class EqualFunc>
bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const {
uint ctr = lookup(key);
- return (_arr[ctr] != NULL);
+ return (_storage[ctr] != NULL);
}
template<class Key, class Val, class HashFunc, class EqualFunc>
@@ -494,15 +486,15 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) co
template<class Key, class Val, class HashFunc, class EqualFunc>
Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
uint ctr = lookupAndCreateIfMissing(key);
- assert(_arr[ctr] != NULL);
- return _arr[ctr]->_value;
+ assert(_storage[ctr] != NULL);
+ return _storage[ctr]->_value;
}
template<class Key, class Val, class HashFunc, class EqualFunc>
const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const {
uint ctr = lookup(key);
- if (_arr[ctr] != NULL)
- return _arr[ctr]->_value;
+ if (_storage[ctr] != NULL)
+ return _storage[ctr]->_value;
else
return _defaultVal;
}
@@ -510,38 +502,50 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) {
uint ctr = lookupAndCreateIfMissing(key);
- assert(_arr[ctr] != NULL);
- _arr[ctr]->_value = val;
+ assert(_storage[ctr] != NULL);
+ _storage[ctr]->_value = val;
}
template<class Key, class Val, class HashFunc, class EqualFunc>
void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
// This is based on code in the Wikipedia article on Hash tables.
- uint i = lookup(key);
- if (_arr[i] == NULL)
+
+ const uint hash = _hash(key);
+ uint i = hash & _mask;
+ uint perturb;
+
+ for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ if (_storage[i] == NULL || _equal(_storage[i]->_key, key))
+ break;
+
+ i = (5 * i + perturb + 1) & _mask;
+ }
+
+ if (_storage[i] == NULL)
return; // key wasn't present, so no work has to be done
+
// If we remove a key, we must check all subsequent keys and possibly
// reinsert them.
uint j = i;
- freeNode(_arr[i]);
- _arr[i] = NULL;
- while (true) {
+ freeNode(_storage[i]);
+ _storage[i] = NULL;
+ for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
// Look at the next table slot
- j = (j + 1) % _arrsize;
+ j = (5 * j + perturb + 1) & _mask;
// If the next slot is empty, we are done
- if (_arr[j] == NULL)
+ if (_storage[j] == NULL)
break;
// Compute the slot where the content of the next slot should normally be,
// assuming an empty table, and check whether we have to move it.
- uint k = _hash(_arr[j]->_key) % _arrsize;
+ uint k = _hash(_storage[j]->_key) & _mask;
if ((j > i && (k <= i || k > j)) ||
(j < i && (k <= i && k > j)) ) {
- _arr[i] = _arr[j];
+ _storage[i] = _storage[j];
i = j;
}
}
- _arr[i] = NULL;
- _nele--;
+ _storage[i] = NULL;
+ _size--;
return;
}
diff --git a/common/iff_container.h b/common/iff_container.h
index 9d477276fc..a70548abd4 100644
--- a/common/iff_container.h
+++ b/common/iff_container.h
@@ -162,7 +162,7 @@ public:
void incBytesRead(uint32 inc) {
bytesRead += inc;
if (bytesRead > size) {
- error("Chunk overead");
+ error("Chunk overread");
}
}
@@ -172,19 +172,23 @@ public:
bytesRead = 0;
}
+ bool hasReadAll() const {
+ return (size - bytesRead) == 0;
+ }
+
void feed() {
if (size % 2) {
size++;
}
- while (!_input->eos() && !eos()) {
+ while (!hasReadAll()) {
readByte();
}
}
// Common::ReadStream implementation
- bool eos() const {
- return (size - bytesRead) == 0;
- }
+ bool eos() const { return _input->eos(); }
+ bool err() const { return _input->err(); }
+ void clearErr() { _input->clearErr(); }
uint32 read(void *dataPtr, uint32 dataSize) {
incBytesRead(dataSize);
@@ -209,7 +213,7 @@ public:
_chunk.feed();
_formChunk.incBytesRead(_chunk.size);
- if (_formChunk.eos())
+ if (_formChunk.hasReadAll())
return 0;
_formChunk.incBytesRead(8);
diff --git a/common/keyboard.h b/common/keyboard.h
index a0ae941a08..6a4445728f 100644
--- a/common/keyboard.h
+++ b/common/keyboard.h
@@ -182,7 +182,7 @@ enum KeyCode {
};
/**
- * List of certan special and some fake 'ascii' values used in keyboard events.
+ * List of certain special and some fake 'ascii' values used in keyboard events.
* The values for the function keys listed here are based on what certain SCUMM
* games expect in their scripts.
* @todo Get rid of the function key values, and instead enforce that engines use
diff --git a/common/md5.cpp b/common/md5.cpp
index edce9d8e4e..4eeb3d9a39 100644
--- a/common/md5.cpp
+++ b/common/md5.cpp
@@ -29,6 +29,7 @@
*/
#include "common/file.h"
+#include "common/fs.h"
#include "common/md5.h"
#include "common/util.h"
#include "common/endian.h"
@@ -256,8 +257,16 @@ bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length) {
warning("md5_file: using a directory FilesystemNode");
return false;
}
+
+ ReadStream *stream = file.openForReading();
+ if (!stream) {
+ warning("md5_file: failed to open '%s'", file.getPath().c_str());
+ return false;
+ }
- return md5_file(file.getPath().c_str(), digest, length);
+ bool result = md5_file(*stream, digest, length);
+ delete stream;
+ return result;
}
bool md5_file(const char *name, uint8 digest[16], uint32 length) {
diff --git a/common/md5.h b/common/md5.h
index e7879dc6df..a8642b1322 100644
--- a/common/md5.h
+++ b/common/md5.h
@@ -26,11 +26,12 @@
#define COMMON_MD5_H
#include "common/scummsys.h"
-#include "common/fs.h"
-#include "common/stream.h"
namespace Common {
+class FilesystemNode;
+class ReadStream;
+
bool md5_file(const char *name, uint8 digest[16], uint32 length = 0);
bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length = 0);
bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length = 0);
diff --git a/common/memorypool.cpp b/common/memorypool.cpp
index f3dfb7975f..12307ba5d6 100644
--- a/common/memorypool.cpp
+++ b/common/memorypool.cpp
@@ -28,22 +28,6 @@
namespace Common {
-static const size_t CHUNK_PAGE_SIZE = 32;
-
-void* MemoryPool::allocPage() {
- void* result = ::malloc(CHUNK_PAGE_SIZE * _chunkSize);
- _pages.push_back(result);
- void* current = result;
- for (size_t i = 1; i < CHUNK_PAGE_SIZE; ++i) {
- void* next = ((char*)current + _chunkSize);
- *(void**)current = next;
-
- current = next;
- }
- *(void**)current = NULL;
- return result;
-}
-
MemoryPool::MemoryPool(size_t chunkSize) {
// You must at least fit the pointer in the node (technically unneeded considering the next rounding statement)
_chunkSize = MAX(chunkSize, sizeof(void*));
@@ -52,38 +36,68 @@ MemoryPool::MemoryPool(size_t chunkSize) {
_chunkSize = (_chunkSize + sizeof(void*) - 1) & (~(sizeof(void*) - 1));
_next = NULL;
+
+ _chunksPerPage = 8;
}
MemoryPool::~MemoryPool() {
- for (size_t i = 0; i<_pages.size(); ++i)
- ::free(_pages[i]);
+ for (size_t i = 0; i < _pages.size(); ++i)
+ ::free(_pages[i].start);
+}
+
+void MemoryPool::allocPage() {
+ Page page;
+
+ // Allocate a new page
+ page.numChunks = _chunksPerPage;
+ page.start = ::malloc(page.numChunks * _chunkSize);
+ assert(page.start);
+ _pages.push_back(page);
+
+ // Next time, we'll alocate a page twice as big as this one.
+ _chunksPerPage *= 2;
+
+ // Add the page to the pool of free chunk
+ addPageToPool(page);
+}
+
+void MemoryPool::addPageToPool(const Page &page) {
+
+ // Add all chunks of the new page to the linked list (pool) of free chunks
+ void *current = page.start;
+ for (size_t i = 1; i < page.numChunks; ++i) {
+ void *next = ((char*)current + _chunkSize);
+ *(void **)current = next;
+
+ current = next;
+ }
+
+ // Last chunk points to the old _next
+ *(void**)current = _next;
+
+ // From now on, the first free chunk is the first chunk of the new page
+ _next = page.start;
}
-void* MemoryPool::malloc() {
-#if 1
- if (!_next)
- _next = allocPage();
+void *MemoryPool::malloc() {
+ if (!_next) // No free chunks left? Allocate a new page
+ allocPage();
- void* result = _next;
+ assert(_next);
+ void *result = _next;
_next = *(void**)result;
return result;
-#else
- return ::malloc(_chunkSize);
-#endif
}
void MemoryPool::free(void* ptr) {
-#if 1
+ // Add the chunk back to (the start of) the list of free chunks
*(void**)ptr = _next;
_next = ptr;
-#else
- ::free(ptr);
-#endif
}
// Technically not compliant C++ to compare unrelated pointers. In practice...
-bool MemoryPool::isPointerInPage(void* ptr, void* page) {
- return (ptr >= page) && (ptr < (char*)page + CHUNK_PAGE_SIZE * _chunkSize);
+bool MemoryPool::isPointerInPage(void *ptr, const Page &page) {
+ return (ptr >= page.start) && (ptr < (char*)page.start + page.numChunks * _chunkSize);
}
void MemoryPool::freeUnusedPages() {
@@ -94,9 +108,10 @@ void MemoryPool::freeUnusedPages() {
numberOfFreeChunksPerPage[i] = 0;
}
- void* iterator = _next;
+ // Compute for each page how many chunks in it are still in use.
+ void *iterator = _next;
while (iterator) {
- // This should be a binary search
+ // TODO: This should be a binary search (requiring us to keep _pages sorted)
for (size_t i = 0; i < _pages.size(); ++i) {
if (isPointerInPage(iterator, _pages[i])) {
++numberOfFreeChunksPerPage[i];
@@ -106,12 +121,32 @@ void MemoryPool::freeUnusedPages() {
iterator = *(void**)iterator;
}
+ // Free all pages which are not in use.
+ // TODO: Might want to reset _chunksPerPage here (e.g. to the largest
+ // _pages[i].numChunks value still in use).
size_t freedPagesCount = 0;
- for (size_t i = 0; i < _pages.size(); ++i) {
- if (numberOfFreeChunksPerPage[i] == CHUNK_PAGE_SIZE) {
- ::free(_pages[i]);
- _pages[i] = NULL; // TODO : Remove NULL values
+ for (size_t i = 0; i < _pages.size(); ++i) {
+ if (numberOfFreeChunksPerPage[i] == _pages[i].numChunks) {
+ // Remove all chunks of this page from the list of free chunks
+ void **iter2 = &_next;
+ while (*iter2) {
+ if (isPointerInPage(*iter2, _pages[i]))
+ *iter2 = **(void***)iter2;
+ else
+ iter2 = *(void***)iter2;
+ }
+ ::free(_pages[i].start);
++freedPagesCount;
+ _pages[i].start = NULL;
+ }
+ }
+
+ for (size_t i = 0; i < _pages.size(); ) {
+ if (_pages[i].start == NULL) {
+ _pages.remove_at(i);
+ // We just removed an entry, so we do not advance "i"
+ } else {
+ ++i;
}
}
diff --git a/common/memorypool.h b/common/memorypool.h
index fcbacabc5c..dd2e8f13a4 100644
--- a/common/memorypool.h
+++ b/common/memorypool.h
@@ -32,26 +32,57 @@
namespace Common {
class MemoryPool {
-private:
+protected:
MemoryPool(const MemoryPool&);
MemoryPool& operator=(const MemoryPool&);
+
+ struct Page {
+ void *start;
+ size_t numChunks;
+ };
size_t _chunkSize;
- Array<void*> _pages;
- void* _next;
+ Array<Page> _pages;
+ void *_next;
+ size_t _chunksPerPage;
+
+ void allocPage();
+ void addPageToPool(const Page &page);
+ bool isPointerInPage(void *ptr, const Page &page);
- void* allocPage();
- bool isPointerInPage(void* ptr, void* page);
public:
MemoryPool(size_t chunkSize);
~MemoryPool();
- void* malloc();
- void free(void* ptr);
+ void *malloc();
+ void free(void *ptr);
void freeUnusedPages();
};
+template<size_t CHUNK_SIZE, size_t NUM_INTERNAL_CHUNKS = 32>
+class FixedSizeMemoryPool : public MemoryPool {
+private:
+ enum {
+ REAL_CHUNK_SIZE = (CHUNK_SIZE + sizeof(void*) - 1) & (~(sizeof(void*) - 1))
+ };
+
+ byte _storage[NUM_INTERNAL_CHUNKS * REAL_CHUNK_SIZE];
+public:
+ FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {
+ assert(REAL_CHUNK_SIZE == _chunkSize);
+ // Insert some static storage
+ Page internalPage = { _storage, NUM_INTERNAL_CHUNKS };
+ addPageToPool(internalPage);
+ }
+};
+
+template<size_t CHUNK_SIZE>
+class FixedSizeMemoryPool<CHUNK_SIZE,0> : public MemoryPool {
+public:
+ FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {}
+};
+
} // End of namespace Common
#endif
diff --git a/common/module.mk b/common/module.mk
index ed15bf75ea..e04af5270b 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -2,6 +2,7 @@ MODULE := common
MODULE_OBJS := \
advancedDetector.o \
+ archive.o \
config-file.o \
config-manager.o \
file.o \
diff --git a/common/ptr.h b/common/ptr.h
index c6fcaa4f75..99bc82a2d3 100644
--- a/common/ptr.h
+++ b/common/ptr.h
@@ -218,8 +218,4 @@ bool operator!=(const Common::SharedPtr<T1> &l, const Common::SharedPtr<T2> &r)
return l.get() != r.get();
}
-
#endif
-
-
-
diff --git a/common/queue.h b/common/queue.h
index cb29c59058..be6df0148a 100644
--- a/common/queue.h
+++ b/common/queue.h
@@ -31,39 +31,62 @@
namespace Common {
/**
- * Variable size Queue class, implemented using our Array class.
+ * Variable size Queue class, implemented using our List class.
*/
template<class T>
class Queue {
-protected:
- List<T> _queue;
public:
- Queue<T>() {}
- Queue<T>(const List<T> &queueContent) : _queue(queueContent) {}
+ typedef T value_type;
+
+public:
+ Queue<T>() : _impl() {}
+ Queue<T>(const Queue<T> &queue) : _impl(queue._impl) {}
+
+ Queue<T> &operator=(const Queue<T> &queue) {
+ _impl = queue._impl;
+ return *this;
+ }
bool empty() const {
- return _queue.empty();
+ return _impl.empty();
}
+
void clear() {
- _queue.clear();
+ _impl.clear();
}
+
void push(const T &x) {
- _queue.push_back(x);
+ _impl.push_back(x);
}
- T back() const {
- return _queue.reverse_begin().operator*();
+
+ T &front() {
+ return *_impl.begin();
}
- T front() const {
- return _queue.begin().operator*();
+
+ const T &front() const {
+ return *_impl.begin();
}
+
+ T &back() {
+ return *_impl.reverse_begin();
+ }
+
+ const T &back() const {
+ return *_impl.reverse_begin();
+ }
+
T pop() {
T tmp = front();
- _queue.pop_front();
+ _impl.pop_front();
return tmp;
}
+
int size() const {
- return _queue.size();
+ return _impl.size();
}
+
+private:
+ List<T> _impl;
};
} // End of namespace Common
diff --git a/common/savefile.h b/common/savefile.h
index f30ddfc160..d44f946d48 100644
--- a/common/savefile.h
+++ b/common/savefile.h
@@ -39,27 +39,14 @@ namespace Common {
* That typically means "save games", but also includes things like the
* IQ points in Indy3.
*/
-class InSaveFile : public SeekableReadStream {};
+typedef SeekableReadStream InSaveFile;
/**
* A class which allows game engines to save game state data.
* That typically means "save games", but also includes things like the
* IQ points in Indy3.
*/
-class OutSaveFile : public WriteStream {
-public:
- /**
- * Close this savefile, to be called right before destruction of this
- * savefile. The idea is that this ways, I/O errors that occur
- * during closing/flushing of the file can still be handled by the
- * game engine.
- *
- * By default, this just flushes the stream.
- */
- virtual void finalize() {
- flush();
- }
-};
+typedef WriteStream OutSaveFile;
/**
diff --git a/common/str.cpp b/common/str.cpp
index 5f8d4ffb7e..6c48738533 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -26,6 +26,13 @@
#include "common/hash-str.h"
#include "common/util.h"
+#include "common/memorypool.h"
+
+#if !defined(__SYMBIAN32__)
+#include <new>
+#endif
+
+
namespace Common {
#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
@@ -34,28 +41,27 @@ const String String::emptyString;
const char *String::emptyString = "";
#endif
-static int computeCapacity(int len) {
- // By default, for the capacity we use the nearest multiple of 32
- // that leaves at least 16 chars of extra space (in case the string
- // grows a bit).
- // Finally, we subtract 1 to compensate for the trailing zero byte.
- len += 16;
- return ((len + 32 - 1) & ~0x1F) - 1;
+
+MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now
+
+static uint32 computeCapacity(uint32 len) {
+ // By default, for the capacity we use the next multiple of 32
+ return ((len + 32 - 1) & ~0x1F);
}
-String::String(const char *str) : _len(0), _str(_storage) {
+String::String(const char *str) : _size(0), _str(_storage) {
if (str == 0) {
_storage[0] = 0;
- _len = 0;
+ _size = 0;
} else
initWithCStr(str, strlen(str));
}
-String::String(const char *str, uint32 len) : _len(0), _str(_storage) {
+String::String(const char *str, uint32 len) : _size(0), _str(_storage) {
initWithCStr(str, len);
}
-String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) {
+String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
assert(endP >= beginP);
initWithCStr(beginP, endP - beginP);
}
@@ -67,13 +73,13 @@ void String::initWithCStr(const char *str, uint32 len) {
// for GCC 2.95.x compatibility (see also tracker item #1602879).
_storage[0] = 0;
- _len = len;
+ _size = len;
if (len >= _builtinCapacity) {
// Not enough internal storage, so allocate more
- _extern._capacity = computeCapacity(len);
+ _extern._capacity = computeCapacity(len+1);
_extern._refCount = 0;
- _str = (char *)malloc(_extern._capacity+1);
+ _str = (char *)malloc(_extern._capacity);
assert(_str != 0);
}
@@ -83,28 +89,30 @@ void String::initWithCStr(const char *str, uint32 len) {
}
String::String(const String &str)
- : _len(str._len), _str(str.isStorageIntern() ? _storage : str._str) {
+ : _size(str._size) {
if (str.isStorageIntern()) {
// String in internal storage: just copy it
memcpy(_storage, str._storage, _builtinCapacity);
+ _str = _storage;
} else {
// String in external storage: use refcount mechanism
str.incRefCount();
_extern._refCount = str._extern._refCount;
_extern._capacity = str._extern._capacity;
+ _str = str._str;
}
assert(_str != 0);
}
String::String(char c)
-: _len(0), _str(_storage) {
+: _size(0), _str(_storage) {
_storage[0] = c;
_storage[1] = 0;
// TODO/FIXME: There is no reason for the following check -- we *do*
// allow strings to contain 0 bytes!
- _len = (c == 0) ? 0 : 1;
+ _size = (c == 0) ? 0 : 1;
}
String::~String() {
@@ -112,16 +120,16 @@ String::~String() {
}
void String::makeUnique() {
- ensureCapacity(_len, true);
+ ensureCapacity(_size, true);
}
/**
- * Ensure that enough storage is available to store at least new_len
+ * Ensure that enough storage is available to store at least new_size
* characters plus a null byte. In addition, if we currently share
* the storage with another string, unshare it, so that we can safely
* write to the storage.
*/
-void String::ensureCapacity(uint32 new_len, bool keep_old) {
+void String::ensureCapacity(uint32 new_size, bool keep_old) {
bool isShared;
uint32 curCapacity, newCapacity;
char *newStorage;
@@ -129,7 +137,7 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
if (isStorageIntern()) {
isShared = false;
- curCapacity = _builtinCapacity - 1;
+ curCapacity = _builtinCapacity;
} else {
isShared = (oldRefCount && *oldRefCount > 1);
curCapacity = _extern._capacity;
@@ -137,30 +145,30 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
// Special case: If there is enough space, and we do not share
// the storage, then there is nothing to do.
- if (!isShared && new_len <= curCapacity)
+ if (!isShared && new_size < curCapacity)
return;
- if (isShared && new_len <= _builtinCapacity - 1) {
+ if (isShared && new_size < _builtinCapacity) {
// We share the storage, but there is enough internal storage: Use that.
newStorage = _storage;
- newCapacity = _builtinCapacity - 1;
+ newCapacity = _builtinCapacity;
} else {
// We need to allocate storage on the heap!
// Compute a suitable new capacity limit
- newCapacity = computeCapacity(new_len);
+ newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
// Allocate new storage
- newStorage = (char *)malloc(newCapacity+1);
+ newStorage = (char *)malloc(newCapacity);
assert(newStorage);
}
// Copy old data if needed, elsewise reset the new storage.
if (keep_old) {
- assert(_len <= newCapacity);
- memcpy(newStorage, _str, _len + 1);
+ assert(_size < newCapacity);
+ memcpy(newStorage, _str, _size + 1);
} else {
- _len = 0;
+ _size = 0;
newStorage[0] = 0;
}
@@ -182,7 +190,11 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) {
void String::incRefCount() const {
assert(!isStorageIntern());
if (_extern._refCount == 0) {
- _extern._refCount = new int(2);
+ if (g_refCountPool == 0)
+ g_refCountPool = new MemoryPool(sizeof(int));
+
+ _extern._refCount = (int *)g_refCountPool->malloc();
+ *_extern._refCount = 2;
} else {
++(*_extern._refCount);
}
@@ -198,7 +210,10 @@ void String::decRefCount(int *oldRefCount) {
if (!oldRefCount || *oldRefCount <= 0) {
// The ref count reached zero, so we free the string storage
// and the ref count storage.
- delete oldRefCount;
+ if (oldRefCount) {
+ assert(g_refCountPool);
+ g_refCountPool->free(oldRefCount);
+ }
free(_str);
// Even though _str points to a freed memory block now,
@@ -210,7 +225,7 @@ void String::decRefCount(int *oldRefCount) {
String& String::operator =(const char *str) {
uint32 len = strlen(str);
ensureCapacity(len, false);
- _len = len;
+ _size = len;
memmove(_str, str, len + 1);
return *this;
}
@@ -221,16 +236,16 @@ String &String::operator =(const String &str) {
if (str.isStorageIntern()) {
decRefCount(_extern._refCount);
- _len = str._len;
+ _size = str._size;
_str = _storage;
- memcpy(_str, str._str, _len + 1);
+ memcpy(_str, str._str, _size + 1);
} else {
str.incRefCount();
decRefCount(_extern._refCount);
_extern._refCount = str._extern._refCount;
_extern._capacity = str._extern._capacity;
- _len = str._len;
+ _size = str._size;
_str = str._str;
}
@@ -240,7 +255,7 @@ String &String::operator =(const String &str) {
String& String::operator =(char c) {
decRefCount(_extern._refCount);
_str = _storage;
- _len = 1;
+ _size = 1;
_str[0] = c;
_str[1] = 0;
return *this;
@@ -249,30 +264,30 @@ String& String::operator =(char c) {
String &String::operator +=(const char *str) {
int len = strlen(str);
if (len > 0) {
- ensureCapacity(_len + len, true);
+ ensureCapacity(_size + len, true);
- memcpy(_str + _len, str, len + 1);
- _len += len;
+ memcpy(_str + _size, str, len + 1);
+ _size += len;
}
return *this;
}
String &String::operator +=(const String &str) {
- int len = str._len;
+ int len = str._size;
if (len > 0) {
- ensureCapacity(_len + len, true);
+ ensureCapacity(_size + len, true);
- memcpy(_str + _len, str._str, len + 1);
- _len += len;
+ memcpy(_str + _size, str._str, len + 1);
+ _size += len;
}
return *this;
}
String &String::operator +=(char c) {
- ensureCapacity(_len + 1, true);
+ ensureCapacity(_size + 1, true);
- _str[_len++] = c;
- _str[_len] = 0;
+ _str[_size++] = c;
+ _str[_size] = 0;
return *this;
}
@@ -293,10 +308,10 @@ bool String::hasPrefix(const char *x) const {
bool String::hasSuffix(const char *x) const {
assert(x != 0);
// Compare x with the end of _str.
- const uint32 x_len = strlen(x);
- if (x_len > _len)
+ const uint32 x_size = strlen(x);
+ if (x_size > _size)
return false;
- const char *y = c_str() + _len - x_len;
+ const char *y = c_str() + _size - x_size;
while (*x && *x == *y) {
++x;
++y;
@@ -315,66 +330,74 @@ bool String::contains(char x) const {
return strchr(c_str(), x) != NULL;
}
+bool String::matchString(const char *pat) const {
+ return Common::matchString(c_str(), pat);
+}
+
+bool String::matchString(const String &pat) const {
+ return Common::matchString(c_str(), pat.c_str());
+}
+
void String::deleteLastChar() {
- deleteChar(_len - 1);
+ deleteChar(_size - 1);
}
void String::deleteChar(uint32 p) {
- assert(p < _len);
+ assert(p < _size);
makeUnique();
- while (p++ < _len)
+ while (p++ < _size)
_str[p-1] = _str[p];
- _len--;
+ _size--;
}
void String::clear() {
decRefCount(_extern._refCount);
- _len = 0;
+ _size = 0;
_str = _storage;
_storage[0] = 0;
}
void String::setChar(char c, uint32 p) {
- assert(p <= _len);
+ assert(p <= _size);
makeUnique();
_str[p] = c;
}
void String::insertChar(char c, uint32 p) {
- assert(p <= _len);
+ assert(p <= _size);
- ensureCapacity(_len + 1, true);
- _len++;
- for (uint32 i = _len; i > p; --i)
+ ensureCapacity(_size + 1, true);
+ _size++;
+ for (uint32 i = _size; i > p; --i)
_str[i] = _str[i-1];
_str[p] = c;
}
void String::toLowercase() {
makeUnique();
- for (uint32 i = 0; i < _len; ++i)
+ for (uint32 i = 0; i < _size; ++i)
_str[i] = tolower(_str[i]);
}
void String::toUppercase() {
makeUnique();
- for (uint32 i = 0; i < _len; ++i)
+ for (uint32 i = 0; i < _size; ++i)
_str[i] = toupper(_str[i]);
}
void String::trim() {
- if (_len == 0)
+ if (_size == 0)
return;
makeUnique();
// Trim trailing whitespace
- while (_len >= 1 && isspace(_str[_len-1]))
- _len--;
- _str[_len] = 0;
+ while (_size >= 1 && isspace(_str[_size-1]))
+ _size--;
+ _str[_size] = 0;
// Trim leading whitespace
char *t = _str;
@@ -382,8 +405,8 @@ void String::trim() {
t++;
if (t != _str) {
- _len -= t - _str;
- memmove(_str, t, _len + 1);
+ _size -= t - _str;
+ memmove(_str, t, _size + 1);
}
}
@@ -524,4 +547,112 @@ char *trim(char *t) {
return rtrim(ltrim(t));
}
+Common::String lastPathComponent(const Common::String &path, const char sep) {
+ const char *str = path.c_str();
+ const char *last = str + path.size();
+
+ // Skip over trailing slashes
+ while (last > str && *(last-1) == sep)
+ --last;
+
+ // Path consisted of only slashes -> return empty string
+ if (last == str)
+ return Common::String();
+
+ // Now scan the whole component
+ const char *first = last - 1;
+ while (first >= str && *first != sep)
+ --first;
+
+ if (*first == sep)
+ first++;
+
+ return Common::String(first, last);
+}
+
+Common::String normalizePath(const Common::String &path, const char sep) {
+ if (path.empty())
+ return path;
+
+ const char *cur = path.c_str();
+ Common::String result;
+
+ // If there is a leading slash, preserve that:
+ if (*cur == sep) {
+ result += sep;
+ while (*cur == sep)
+ ++cur;
+ }
+
+ // Scan till the end of the String
+ while (*cur != 0) {
+ const char *start = cur;
+
+ // Scan till the next path separator resp. the end of the string
+ while (*cur != sep && *cur != 0)
+ cur++;
+
+ const Common::String component(start, cur);
+
+ // Skip empty components and dot components, add all others
+ if (!component.empty() && component != ".") {
+ // Add a separator before the component, unless the result
+ // string already ends with one (which happens only if the
+ // path *starts* with a separator).
+ if (!result.empty() && result.lastChar() != sep)
+ result += sep;
+
+ // Add the component
+ result += component;
+ }
+
+ // Skip over separator chars
+ while (*cur == sep)
+ cur++;
+ }
+
+ return result;
+}
+
+bool matchString(const char *str, const char *pat) {
+ assert(str);
+ assert(pat);
+
+ const char *p = 0;
+ const char *q = 0;
+
+ for (;;) {
+ switch (*pat) {
+ case '*':
+ // Record pattern / string possition for backtracking
+ p = ++pat;
+ q = str;
+ // If pattern ended with * -> match
+ if (!*pat)
+ return true;
+ break;
+
+ default:
+ if (*pat != *str) {
+ if (p) {
+ // No match, oops -> try to backtrack
+ pat = p;
+ str = ++q;
+ if (!*str)
+ return !*pat;
+ break;
+ }
+ else
+ return false;
+ }
+ // fallthrough
+ case '?':
+ if (!*str)
+ return !*pat;
+ pat++;
+ str++;
+ }
+ }
+}
+
} // End of namespace Common
diff --git a/common/str.h b/common/str.h
index 3479fee8e4..772718a087 100644
--- a/common/str.h
+++ b/common/str.h
@@ -54,14 +54,14 @@ protected:
* than 8 makes no sense, since that's the size of member _extern
* (on 32 bit machines; 12 bytes on systems with 64bit pointers).
*/
- static const uint32 _builtinCapacity = 32;
+ static const uint32 _builtinCapacity = 32 - sizeof(uint32) - sizeof(char*);
/**
* Length of the string. Stored to avoid having to call strlen
* a lot. Yes, we limit ourselves to strings shorter than 4GB --
* on purpose :-).
*/
- uint32 _len;
+ uint32 _size;
/**
* Pointer to the actual string storage. Either points to _storage,
@@ -97,7 +97,7 @@ public:
#endif
/** Construct a new empty string. */
- String() : _len(0), _str(_storage) { _storage[0] = 0; }
+ String() : _size(0), _str(_storage) { _storage[0] = 0; }
/** Construct a new string from the given NULL-terminated C string. */
String(const char *str);
@@ -149,14 +149,38 @@ public:
bool contains(const char *x) const;
bool contains(char x) const;
+ /**
+ * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
+ * Taken from exult/files/listfiles.cc
+ *
+ * Token meaning:
+ * "*": any character, any amount of times.
+ * "?": any character, only once.
+ *
+ * Example strings/patterns:
+ * String: monkey.s01 Pattern: monkey.s?? => true
+ * String: monkey.s101 Pattern: monkey.s?? => false
+ * String: monkey.s99 Pattern: monkey.s?1 => false
+ * String: monkey.s101 Pattern: monkey.s* => true
+ * String: monkey.s99 Pattern: monkey.s*1 => false
+ *
+ * @param str Text to be matched against the given pattern.
+ * @param pat Glob pattern.
+ *
+ * @return true if str matches the pattern, false otherwise.
+ */
+ bool matchString(const char *pat) const;
+ bool matchString(const String &pat) const;
+
+
inline const char *c_str() const { return _str; }
- inline uint size() const { return _len; }
+ inline uint size() const { return _size; }
- inline bool empty() const { return (_len == 0); }
- char lastChar() const { return (_len > 0) ? _str[_len-1] : 0; }
+ inline bool empty() const { return (_size == 0); }
+ char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; }
char operator [](int idx) const {
- assert(_str && idx >= 0 && idx < (int)_len);
+ assert(_str && idx >= 0 && idx < (int)_size);
return _str[idx];
}
@@ -172,11 +196,19 @@ public:
/** Set character c at position p. */
void insertChar(char c, uint32 p);
+ /** Clears the string, making it empty. */
void clear();
+ /** Convert all characters in the string to lowercase. */
void toLowercase();
+
+ /** Convert all characters in the string to uppercase. */
void toUppercase();
+ /**
+ * Removes trailing and leading whitespaces. Uses isspace() to decide
+ * what is whitespace and what not.
+ */
void trim();
uint hash() const;
@@ -203,7 +235,7 @@ public:
protected:
void makeUnique();
- void ensureCapacity(uint32 new_len, bool keep_old);
+ void ensureCapacity(uint32 new_size, bool keep_old);
void incRefCount() const;
void decRefCount(int *oldRefCount);
void initWithCStr(const char *str, uint32 len);
@@ -218,7 +250,7 @@ String operator +(const String &x, const char *y);
String operator +(const String &x, char y);
String operator +(char x, const String &y);
-// Some useful additional comparision operators for Strings
+// Some useful additional comparison operators for Strings
bool operator == (const char *x, const String &y);
bool operator != (const char *x, const String &y);
@@ -227,16 +259,67 @@ extern char *ltrim(char *t);
extern char *rtrim(char *t);
extern char *trim(char *t);
+
+/**
+ * Returns the last component of a given path.
+ *
+ * Examples:
+ * /foo/bar.txt would return 'bar.txt'
+ * /foo/bar/ would return 'bar'
+ * /foo/./bar// would return 'bar'
+ *
+ * @param path the path of which we want to know the last component
+ * @param sep character used to separate path components
+ * @return The last component of the path.
+ */
+Common::String lastPathComponent(const Common::String &path, const char sep);
+
+/**
+ * Normalize a gien path to a canonical form. In particular:
+ * - trailing separators are removed: /foo/bar/ -> /foo/bar
+ * - double separators (= empty components) are removed: /foo//bar -> /foo/bar
+ * - dot components are removed: /foo/./bar -> /foo/bar
+ *
+ * @todo remove double dot components: /foo/baz/../bar -> /foo/bar
+ *
+ * @param path the path to normalize
+ * @param sep the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff)
+ * @return the normalized path
+ */
+Common::String normalizePath(const Common::String &path, const char sep);
+
+
+/**
+ * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
+ * Taken from exult/files/listfiles.cc
+ *
+ * Token meaning:
+ * "*": any character, any amount of times.
+ * "?": any character, only once.
+ *
+ * Example strings/patterns:
+ * String: monkey.s01 Pattern: monkey.s?? => true
+ * String: monkey.s101 Pattern: monkey.s?? => false
+ * String: monkey.s99 Pattern: monkey.s?1 => false
+ * String: monkey.s101 Pattern: monkey.s* => true
+ * String: monkey.s99 Pattern: monkey.s*1 => false
+ *
+ * @param str Text to be matched against the given pattern.
+ * @param pat Glob pattern.
+ *
+ * @return true if str matches the pattern, false otherwise.
+ */
+bool matchString(const char *str, const char *pat);
+
+
class StringList : public Array<String> {
public:
void push_back(const char *str) {
- ensureCapacity(_size + 1);
- _data[_size++] = str;
+ Array<String>::push_back(str);
}
void push_back(const String &str) {
- ensureCapacity(_size + 1);
- _data[_size++] = str;
+ Array<String>::push_back(str);
}
};
diff --git a/common/stream.cpp b/common/stream.cpp
index e06cc28415..9bcc29550f 100644
--- a/common/stream.cpp
+++ b/common/stream.cpp
@@ -43,8 +43,10 @@ MemoryReadStream *ReadStream::readStream(uint32 dataSize) {
uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
// Read at most as many bytes as are still available...
- if (dataSize > _size - _pos)
+ if (dataSize > _size - _pos) {
dataSize = _size - _pos;
+ _eos = true;
+ }
memcpy(dataPtr, _ptr, dataSize);
if (_encbyte) {
@@ -60,7 +62,7 @@ uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) {
return dataSize;
}
-void MemoryReadStream::seek(int32 offs, int whence) {
+bool MemoryReadStream::seek(int32 offs, int whence) {
// Pre-Condition
assert(_pos <= _size);
switch (whence) {
@@ -81,12 +83,16 @@ void MemoryReadStream::seek(int32 offs, int whence) {
}
// Post-Condition
assert(_pos <= _size);
+
+ // Reset end-of-stream flag on a successful seek
+ _eos = false;
+ return true; // FIXME: STREAM REWRITE
}
#define LF 0x0A
#define CR 0x0D
-char *SeekableReadStream::readLine(char *buf, size_t bufSize) {
+char *SeekableReadStream::readLine_OLD(char *buf, size_t bufSize) {
assert(buf && bufSize > 0);
char *p = buf;
size_t len = 0;
@@ -156,19 +162,27 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) {
// If end-of-file occurs before any characters are read, return NULL
// and the buffer contents remain unchanged.
- if (eos() || ioFailed()) {
+ if (eos() || err()) {
return 0;
}
- // Loop as long as the stream has not ended, there is still free
- // space in the buffer, and the line has not ended
- while (!eos() && len + 1 < bufSize && c != LF) {
+ // Loop as long as there is still free space in the buffer,
+ // and the line has not ended
+ while (len + 1 < bufSize && c != LF) {
c = readByte();
-
- // If end-of-file occurs before any characters are read, return
- // NULL and the buffer contents remain unchanged. If an error
- /// occurs, return NULL and the buffer contents are indeterminate.
- if (ioFailed() || (len == 0 && eos()))
+
+ if (eos()) {
+ // If end-of-file occurs before any characters are read, return
+ // NULL and the buffer contents remain unchanged.
+ if (len == 0)
+ return 0;
+
+ break;
+ }
+
+ // If an error occurs, return NULL and the buffer contents
+ // are indeterminate.
+ if (err())
return 0;
// Check for CR or CR/LF
@@ -178,8 +192,18 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) {
if (c == CR) {
// Look at the next char -- is it LF? If not, seek back
c = readByte();
- if (c != LF && !eos())
+
+ if (err()) {
+ return 0; // error: the buffer contents are indeterminate
+ }
+ if (eos()) {
+ // The CR was the last character in the file.
+ // Reset the eos() flag since we successfully finished a line
+ clearErr();
+ } else if (c != LF) {
seek(-1, SEEK_CUR);
+ }
+
// Treat CR & CR/LF as plain LF
c = LF;
}
@@ -188,25 +212,37 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) {
len++;
}
- // FIXME:
- // This should fix a bug while using readLine with Common::File
- // it seems that it sets the eos flag after an invalid read
- // and at the same time the ioFailed flag
- // the config file parser fails out of that reason for the new themes
- if (eos()) {
- clearIOFailed();
- }
-
// We always terminate the buffer if no error occured
*p = 0;
return buf;
}
+String SeekableReadStream::readLine() {
+ // Read a line
+ String line;
+ while (line.lastChar() != '\n') {
+ char buf[256];
+ if (!readLine_NEW(buf, 256))
+ break;
+ line += buf;
+ }
+
+ if (line.lastChar() == '\n')
+ line.deleteLastChar();
+
+ return line;
+}
+
+
uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) {
- dataSize = MIN(dataSize, _end - _pos);
+ if (dataSize > _end - _pos) {
+ dataSize = _end - _pos;
+ _eos = true;
+ }
dataSize = _parentStream->read(dataPtr, dataSize);
+ _eos |= _parentStream->eos();
_pos += dataSize;
return dataSize;
@@ -219,9 +255,10 @@ SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, u
assert(_begin <= _end);
_pos = _begin;
_parentStream->seek(_pos);
+ _eos = false;
}
-void SeekableSubReadStream::seek(int32 offset, int whence) {
+bool SeekableSubReadStream::seek(int32 offset, int whence) {
assert(_pos >= _begin);
assert(_pos <= _end);
@@ -239,7 +276,10 @@ void SeekableSubReadStream::seek(int32 offset, int whence) {
assert(_pos >= _begin);
assert(_pos <= _end);
- _parentStream->seek(_pos);
+ bool ret = _parentStream->seek(_pos);
+ if (ret) _eos = false; // reset eos on successful seek
+
+ return ret;
}
BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream)
@@ -304,7 +344,7 @@ BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *paren
_parentStream(parentStream) {
}
-void BufferedSeekableReadStream::seek(int32 offset, int whence) {
+bool BufferedSeekableReadStream::seek(int32 offset, int whence) {
// If it is a "local" seek, we may get away with "seeking" around
// in the buffer only.
// Note: We could try to handle SEEK_END and SEEK_SET, too, but
@@ -319,6 +359,8 @@ void BufferedSeekableReadStream::seek(int32 offset, int whence) {
_pos = _bufSize;
_parentStream->seek(offset, whence);
}
+
+ return true; // FIXME: STREAM REWRITE
}
} // End of namespace Common
diff --git a/common/stream.h b/common/stream.h
index c19db3a9a5..02677e0dbb 100644
--- a/common/stream.h
+++ b/common/stream.h
@@ -41,19 +41,30 @@ public:
virtual ~Stream() {}
/**
- * Returns true if any I/O failure occurred.
- * This flag is never cleared automatically. In order to clear it,
- * client code has to call clearIOFailed() explicitly.
- *
- * @todo Instead of returning a plain bool, maybe we should define
- * a list of error codes which can be returned here.
+ * DEPRECATED: Use err() or eos() instead.
+ * Returns true if any I/O failure occurred or the end of the
+ * stream was reached while reading.
*/
- virtual bool ioFailed() const { return false; }
+ virtual bool ioFailed() const { return err(); }
/**
+ * DEPRECATED: Don't use this unless you are still using ioFailed().
* Reset the I/O error status.
*/
- virtual void clearIOFailed() {}
+ virtual void clearIOFailed() { clearErr(); }
+
+ /**
+ * Returns true if an I/O failure occurred.
+ * This flag is never cleared automatically. In order to clear it,
+ * client code has to call clearErr() explicitly.
+ */
+ virtual bool err() const { return false; }
+
+ /**
+ * Reset the I/O error status as returned by err().
+ * For a ReadStream, also reset the end-of-stream status returned by eos().
+ */
+ virtual void clearErr() {}
};
/**
@@ -75,8 +86,26 @@ public:
* Commit any buffered data to the underlying channel or
* storage medium; unbuffered streams can use the default
* implementation.
+ *
+ * @return true on success, false in case of a failure
*/
- virtual void flush() {}
+ virtual bool flush() { return true; }
+
+ /**
+ * Finalize and close this stream. To be called right before this
+ * stream instance is deleted. The goal here is to enable calling
+ * code to detect and handle I/O errors which might occur when
+ * closing (and this flushing, if buffered) the stream.
+ *
+ * After this method has been called, no further writes may be
+ * performed on the stream. Calling err() is allowed.
+ *
+ * By default, this just flushes the stream.
+ */
+ virtual void finalize() {
+ flush();
+ }
+
// The remaining methods all have default implementations; subclasses
// need not (and should not) overload them.
@@ -135,7 +164,9 @@ public:
class ReadStream : virtual public Stream {
public:
/**
- * Returns true if the end of the stream has been reached.
+ * Returns true if a read failed because the stream has been reached.
+ * This flag is cleared by clearErr().
+ * For a SeekableReadStream, it is also cleared by a successful seek.
*/
virtual bool eos() const = 0;
@@ -151,13 +182,19 @@ public:
// The remaining methods all have default implementations; subclasses
- // need not (and should not) overload them.
+ // in general should not overload them.
+
+ /**
+ * DEPRECATED
+ * Default implementation for backward compatibility
+ */
+ virtual bool ioFailed() { return (eos() || err()); }
/**
- * Read am unsigned byte from the stream and return it.
+ * Read an unsigned byte from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
byte readByte() {
byte b = 0;
@@ -169,7 +206,7 @@ public:
* Read a signed byte from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
int8 readSByte() {
int8 b = 0;
@@ -182,7 +219,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
uint16 readUint16LE() {
uint16 a = readByte();
@@ -195,7 +232,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
uint32 readUint32LE() {
uint32 a = readUint16LE();
@@ -208,7 +245,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
uint16 readUint16BE() {
uint16 b = readByte();
@@ -221,7 +258,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
uint32 readUint32BE() {
uint32 b = readUint16BE();
@@ -234,7 +271,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
int16 readSint16LE() {
return (int16)readUint16LE();
@@ -245,7 +282,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
int32 readSint32LE() {
return (int32)readUint32LE();
@@ -256,7 +293,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
int16 readSint16BE() {
return (int16)readUint16BE();
@@ -267,7 +304,7 @@ public:
* from the stream and return it.
* Performs no error checking. The return value is undefined
* if a read error occurred (for which client code can check by
- * calling ioFailed()).
+ * calling err() and eos() ).
*/
int32 readSint32BE() {
return (int32)readUint32BE();
@@ -277,7 +314,9 @@ public:
* Read the specified amount of data into a malloc'ed buffer
* which then is wrapped into a MemoryReadStream.
* The returned stream might contain less data than requested,
- * if reading more failed.
+ * if reading more failed, because of an I/O error or because
+ * the end of the stream was reached. Which can be determined by
+ * calling err() and eos().
*/
MemoryReadStream *readStream(uint32 dataSize);
@@ -287,57 +326,89 @@ public:
/**
* Interface for a seekable & readable data stream.
*
- * @todo We really need better error handling here!
- * Like seek should somehow indicate whether it failed.
+ * @todo Get rid of SEEK_SET, SEEK_CUR, or SEEK_END, use our own constants
*/
class SeekableReadStream : virtual public ReadStream {
public:
- virtual uint32 pos() const = 0;
- virtual uint32 size() const = 0;
-
- virtual void seek(int32 offset, int whence = SEEK_SET) = 0;
-
- void skip(uint32 offset) { seek(offset, SEEK_CUR); }
-
/**
- * Read one line of text from a CR or CR/LF terminated plain text file.
- * This method is a rough analog of the (f)gets function.
+ * Obtains the current value of the stream position indicator of the
+ * stream.
*
- * @bug A main difference (and flaw) in this function is that there is no
- * way to detect that a line exceeeds the length of the buffer.
- * Code which needs this should use the new readLine_NEW() method instead.
+ * @return the current position indicator, or -1 if an error occurred.
+ */
+ virtual int32 pos() const = 0;
+
+ /**
+ * Obtains the total size of the stream, measured in bytes.
+ * If this value is unknown or can not be computed, -1 is returned.
*
- * @param buf the buffer to store into
- * @param bufSize the size of the buffer
- * @return a pointer to the read string, or NULL if an error occurred
+ * @return the size of the stream, or -1 if an error occurred
+ */
+ virtual int32 size() const = 0;
+
+ /**
+ * Sets the stream position indicator for the stream. The new position,
+ * measured in bytes, is obtained by adding offset bytes to the position
+ * specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or
+ * SEEK_END, the offset is relative to the start of the file, the current
+ * position indicator, or end-of-file, respectively. A successful call
+ * to the seek() method clears the end-of-file indicator for the stream.
*
- * @note The line terminator (CR or CR/LF) is stripped and not inserted
- * into the buffer.
+ * @param offset the relative offset in bytes
+ * @param whence the seek reference: SEEK_SET, SEEK_CUR, or SEEK_END
+ * @return true on success, false in case of a failure
+ */
+ virtual bool seek(int32 offset, int whence = SEEK_SET) = 0;
+
+ /**
+ * TODO: Get rid of this??? Or keep it and document it
+ * @return true on success, false in case of a failure
+ */
+ virtual bool skip(uint32 offset) { return seek(offset, SEEK_CUR); }
+
+ /**
+ * DEPRECATED: Do not use this method! Instead use readLine_NEW() or readline().
*/
- virtual char *readLine(char *buf, size_t bufSize);
+ virtual char *readLine_OLD(char *buf, size_t bufSize);
/**
* Reads at most one less than the number of characters specified
* by bufSize from the and stores them in the string buf. Reading
- * stops when the end of a line is reached (CR, CR/LF or LF), at
- * end-of-file or error. The newline, if any, is retained (CR and
- * CR/LF are translated to LF = 0xA = '\n'). If any characters are
- * read and there is no error, a `\0' character is appended to end
- * the string.
+ * stops when the end of a line is reached (CR, CR/LF or LF), and
+ * at end-of-file or error. The newline, if any, is retained (CR
+ * and CR/LF are translated to LF = 0xA = '\n'). If any characters
+ * are read and there is no error, a `\0' character is appended
+ * to end the string.
*
* Upon successful completion, return a pointer to the string. If
* end-of-file occurs before any characters are read, returns NULL
* and the buffer contents remain unchanged. If an error occurs,
* returns NULL and the buffer contents are indeterminate.
* This method does not distinguish between end-of-file and error;
- * callers muse use ioFailed() or eos() to determine which occurred.
+ * callers must use err() or eos() to determine which occurred.
+ *
+ * @note This methods is closely modeled after the standard fgets()
+ * function from stdio.h.
*
* @param buf the buffer to store into
* @param bufSize the size of the buffer
* @return a pointer to the read string, or NULL if an error occurred
*/
virtual char *readLine_NEW(char *s, size_t bufSize);
+
+
+ /**
+ * Reads a full line and returns it as a Common::String. Reading
+ * stops when the end of a line is reached (CR, CR/LF or LF), and
+ * at end-of-file or error.
+ *
+ * Upon successful completion, return a string with the content
+ * of the line, *without* the end of a line marker. This method
+ * does not indicate whether an error occured. Callers muse use
+ * ioFailed() or eos() to determine whether an exception occurred.
+ */
+ virtual String readLine();
};
/**
@@ -353,19 +424,23 @@ protected:
bool _disposeParentStream;
uint32 _pos;
uint32 _end;
+ bool _eos;
public:
SubReadStream(ReadStream *parentStream, uint32 end, bool disposeParentStream = false)
: _parentStream(parentStream),
+ _disposeParentStream(disposeParentStream),
_pos(0),
_end(end),
- _disposeParentStream(disposeParentStream) {
+ _eos(false) {
assert(parentStream);
}
~SubReadStream() {
if (_disposeParentStream) delete _parentStream;
}
- virtual bool eos() const { return _pos == _end; }
+ virtual bool eos() const { return _eos; }
+ virtual bool err() const { return _parentStream->err(); }
+ virtual void clearErr() { _eos = false; _parentStream->clearErr(); }
virtual uint32 read(void *dataPtr, uint32 dataSize);
};
@@ -381,10 +456,10 @@ protected:
public:
SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool disposeParentStream = false);
- virtual uint32 pos() const { return _pos - _begin; }
- virtual uint32 size() const { return _end - _begin; }
+ virtual int32 pos() const { return _pos - _begin; }
+ virtual int32 size() const { return _end - _begin; }
- virtual void seek(int32 offset, int whence = SEEK_SET);
+ virtual bool seek(int32 offset, int whence = SEEK_SET);
};
/**
@@ -437,6 +512,8 @@ public:
virtual bool eos() const { return (_pos == _bufSize) && _parentStream->eos(); }
virtual bool ioFailed() const { return _parentStream->ioFailed(); }
virtual void clearIOFailed() { _parentStream->clearIOFailed(); }
+ virtual bool err() const { return _parentStream->err(); }
+ virtual void clearErr() { _parentStream->clearErr(); }
virtual uint32 read(void *dataPtr, uint32 dataSize);
};
@@ -451,10 +528,10 @@ protected:
public:
BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false);
- virtual uint32 pos() const { return _parentStream->pos() - (_bufSize - _pos); }
- virtual uint32 size() const { return _parentStream->size(); }
+ virtual int32 pos() const { return _parentStream->pos() - (_bufSize - _pos); }
+ virtual int32 size() const { return _parentStream->size(); }
- virtual void seek(int32 offset, int whence = SEEK_SET);
+ virtual bool seek(int32 offset, int whence = SEEK_SET);
};
@@ -471,6 +548,7 @@ private:
uint32 _pos;
byte _encbyte;
bool _disposeMemory;
+ bool _eos;
public:
@@ -485,7 +563,8 @@ public:
_size(dataSize),
_pos(0),
_encbyte(0),
- _disposeMemory(disposeMemory) {}
+ _disposeMemory(disposeMemory),
+ _eos(false) {}
~MemoryReadStream() {
if (_disposeMemory)
@@ -496,11 +575,13 @@ public:
uint32 read(void *dataPtr, uint32 dataSize);
- bool eos() const { return _pos == _size; }
- uint32 pos() const { return _pos; }
- uint32 size() const { return _size; }
+ bool eos() const { return _eos; }
+ void clearErr() { _eos = false; }
+
+ int32 pos() const { return _pos; }
+ int32 size() const { return _size; }
- void seek(int32 offs, int whence = SEEK_SET);
+ bool seek(int32 offs, int whence = SEEK_SET);
};
@@ -553,14 +634,13 @@ public:
return dataSize;
}
- bool eos() const { return _pos == _bufSize; }
uint32 pos() const { return _pos; }
uint32 size() const { return _bufSize; }
};
-/**
+/**
* A sort of hybrid between MemoryWriteStream and Array classes. A stream
- * that grows as it's written to.
+ * that grows as it's written to.
*/
class MemoryWriteStreamDynamic : public Common::WriteStream {
private:
@@ -607,7 +687,6 @@ public:
return dataSize;
}
- bool eos() const { return false; }
uint32 pos() const { return _pos; }
uint32 size() const { return _size; }
diff --git a/common/system.cpp b/common/system.cpp
index 8d528258f4..d9bc027e91 100644
--- a/common/system.cpp
+++ b/common/system.cpp
@@ -28,12 +28,9 @@
#include "common/config-manager.h"
#include "common/system.h"
-#include "common/timer.h"
-#include "common/util.h"
#include "graphics/colormasks.h"
#include "gui/message.h"
-#include "sound/mixer.h"
OSystem *g_system = 0;
@@ -118,6 +115,63 @@ Common::EventManager *OSystem::getEventManager() {
void OSystem::clearScreen() {
Graphics::Surface *screen = lockScreen();
- memset(screen->pixels, 0, screen->h * screen->pitch);
+ if (screen && screen->pixels)
+ memset(screen->pixels, 0, screen->h * screen->pitch);
unlockScreen();
}
+
+
+/*
+FIXME: The config file loading code below needs to be cleaned up.
+ Port specific variants should be pushed into the respective ports.
+
+ Ideally, the default OSystem::openConfigFileForReading/Writing methods
+ should be removed completely.
+*/
+
+
+#ifdef __PLAYSTATION2__
+#include "backends/platform/ps2/systemps2.h"
+#endif
+
+#ifdef IPHONE
+#include "backends/platform/iphone/osys_iphone.h"
+#endif
+
+
+#if defined(UNIX)
+#define DEFAULT_CONFIG_FILE ".scummvmrc"
+#else
+#define DEFAULT_CONFIG_FILE "scummvm.ini"
+#endif
+
+static Common::String getDefaultConfigFileName() {
+ char configFile[MAXPATHLEN];
+#if defined(PALMOS_MODE)
+ strcpy(configFile,"/PALM/Programs/ScummVM/" DEFAULT_CONFIG_FILE);
+#elif defined(IPHONE)
+ strcpy(configFile, OSystem_IPHONE::getConfigPath());
+#elif defined(__PLAYSTATION2__)
+ ((OSystem_PS2*)g_system)->makeConfigPath(configFile);
+#elif defined(__PSP__)
+ strcpy(configFile, "ms0:/" DEFAULT_CONFIG_FILE);
+#else
+ strcpy(configFile, DEFAULT_CONFIG_FILE);
+#endif
+
+ return configFile;
+}
+
+Common::SeekableReadStream *OSystem::openConfigFileForReading() {
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForReading();
+}
+
+Common::WriteStream *OSystem::openConfigFileForWriting() {
+#ifdef __DC__
+ return 0;
+#else
+ Common::FilesystemNode file(getDefaultConfigFileName());
+ return file.openForWriting();
+#endif
+}
diff --git a/common/system.h b/common/system.h
index b895a5cfba..cb9dbedad7 100644
--- a/common/system.h
+++ b/common/system.h
@@ -43,7 +43,10 @@ namespace Common {
struct Event;
class EventManager;
class SaveFileManager;
+ class SearchSet;
class TimerManager;
+ class SeekableReadStream;
+ class WriteStream;
}
class FilesystemFactory;
@@ -900,10 +903,37 @@ public:
/**
* Returns the FilesystemFactory object, depending on the current architecture.
*
- * @return FilesystemFactory* The specific factory for the current architecture.
+ * @return the FSNode factory for the current architecture
*/
virtual FilesystemFactory *getFilesystemFactory() = 0;
+ /**
+ * Add system specific Common::Archive objects to the given SearchSet.
+ * E.g. on Unix the dir corresponding to DATA_PATH (if set), or on
+ * Mac OS X the 'Resource' dir in the app bundle.
+ *
+ * @todo Come up with a better name. This one sucks.
+ *
+ * @param s the SearchSet to which the system specific dirs, if any, are added
+ * @param priority the priority with which those dirs are added
+ */
+ virtual void addSysArchivesToSearchSet(Common::SearchSet &s, uint priority = 0) {}
+
+ /**
+ * Open the default config file for reading, by returning a suitable
+ * ReadStream instance. It is the callers responsiblity to delete
+ * the stream after use.
+ */
+ virtual Common::SeekableReadStream *openConfigFileForReading();
+
+ /**
+ * Open the default config file for writing, by returning a suitable
+ * WriteStream instance. It is the callers responsiblity to delete
+ * the stream after use.
+ *
+ * May return 0 to indicate that writing to config file is not possible.
+ */
+ virtual Common::WriteStream *openConfigFileForWriting();
/**
* Return String which is used for backend-specific addition to theme
diff --git a/common/unarj.cpp b/common/unarj.cpp
index da88c11fc9..244a296efb 100644
--- a/common/unarj.cpp
+++ b/common/unarj.cpp
@@ -23,28 +23,9 @@
*
*/
-// Heavily based on Unarj 2.65
-
-/* UNARJ.C, UNARJ, R JUNG, 06/05/02
- * Main Extractor routine
- * Copyright (c) 1991-2002 by ARJ Software, Inc. All rights reserved.
- *
- * This code may be freely used in programs that are NOT ARJ archivers
- * (both compress and extract ARJ archives).
- *
- * If you wish to distribute a modified version of this program, you
- * MUST indicate that it is a modified version both in the program and
- * source code.
- *
- * We are holding the copyright on the source code, so please do not
- * delete our name from the program files or from the documentation.
- *
- * We wish to give credit to Haruhiko Okumura for providing the
- * basic ideas for ARJ and UNARJ in his program AR. Please note
- * that UNARJ is significantly different from AR from an archive
- * structural point of view.
- *
- */
+//
+// This file is heavily based on the arj code available under the GPL
+// from http://arj.sourceforge.net/ , version 3.10.22 .
#include "common/scummsys.h"
#include "common/util.h"
@@ -52,18 +33,38 @@
namespace Common {
+#define HEADER_ID 0xEA60
+#define HEADER_ID_HI 0xEA
+#define HEADER_ID_LO 0x60
+
+#define FIRST_HDR_SIZE 30
+#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + ARJ_FILENAME_MAX + ARJ_COMMENT_MAX)
+#define CRC_MASK 0xFFFFFFFFL
+#define HSLIMIT_ARJ 524288L
+
+#define CBIT 9
+#define PBIT 5
+#define TBIT 5
+
+//
+// Source for InitCRC, GetCRC: crc32.c
+//
+
static uint32 CRCtable[256];
static void InitCRC(void) {
const uint32 poly = 0xEDB88320;
int i, j;
- uint32 n;
+ uint32 r;
for (i = 0; i < 256; i++) {
- n = i;
+ r = i;
for (j = 0; j < 8; j++)
- n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1);
- CRCtable[i] = n;
+ if (r & 1)
+ r = (r >> 1) ^ poly;
+ else
+ r >>= 1;
+ CRCtable[i] = r;
}
}
@@ -75,7 +76,7 @@ static uint32 GetCRC(byte *data, int len) {
return CRC ^ 0xFFFFFFFF;
}
-ArjFile::ArjFile() {
+ArjFile::ArjFile() : _uncompressedData(NULL) {
InitCRC();
_isOpen = false;
_fallBack = false;
@@ -124,41 +125,47 @@ void ArjFile::registerArchive(const String &filename) {
debug(0, "ArjFile::registerArchive(%s): Located %d files", filename.c_str(), _headers.size());
}
+//
+// Source for findHeader and readHeader: arj_arcv.c
+//
+
int32 ArjFile::findHeader(void) {
- long arcpos, lastpos;
- int c;
+ long end_pos, tmp_pos;
+ int id;
byte header[HEADERSIZE_MAX];
uint32 crc;
- uint16 headersize;
+ uint16 basic_hdr_size;
- arcpos = _currArchive.pos();
+ tmp_pos = _currArchive.pos();
_currArchive.seek(0L, SEEK_END);
- lastpos = _currArchive.pos() - 2;
- if (lastpos > MAXSFX)
- lastpos = MAXSFX;
-
- for ( ; arcpos < lastpos; arcpos++) {
- _currArchive.seek(arcpos, SEEK_SET);
- c = _currArchive.readByte();
- while (arcpos < lastpos) {
- if (c != HEADER_ID_LO) // low order first
- c = _currArchive.readByte();
- else if ((c = _currArchive.readByte()) == HEADER_ID_HI)
- break;
- arcpos++;
+ end_pos = _currArchive.pos() - 2;
+ if (end_pos >= tmp_pos + HSLIMIT_ARJ)
+ end_pos = tmp_pos + HSLIMIT_ARJ;
+
+ while (tmp_pos < end_pos) {
+ _currArchive.seek(tmp_pos, SEEK_SET);
+ id = _currArchive.readByte();
+ while (tmp_pos < end_pos) {
+ if (id == HEADER_ID_LO)
+ if ((id = _currArchive.readByte()) == HEADER_ID_HI)
+ break;
+ else
+ id = _currArchive.readByte();
+ tmp_pos++;
}
- if (arcpos >= lastpos)
- break;
- if ((headersize = _currArchive.readUint16LE()) <= HEADERSIZE_MAX) {
- _currArchive.read(header, headersize);
- crc = GetCRC(header, headersize);
+ if (tmp_pos >= end_pos)
+ return -1;
+ if ((basic_hdr_size = _currArchive.readUint16LE()) <= HEADERSIZE_MAX) {
+ _currArchive.read(header, basic_hdr_size);
+ crc = GetCRC(header, basic_hdr_size);
if (crc == _currArchive.readUint32LE()) {
- _currArchive.seek(arcpos, SEEK_SET);
- return arcpos;
+ _currArchive.seek(tmp_pos, SEEK_SET);
+ return tmp_pos;
}
}
+ tmp_pos++;
}
- return -1; // could not find a valid header
+ return -1;
}
ArjHeader *ArjFile::readHeader() {
@@ -166,6 +173,7 @@ ArjHeader *ArjFile::readHeader() {
ArjHeader *head;
byte headData[HEADERSIZE_MAX];
+ // Strictly check the header ID
header.id = _currArchive.readUint16LE();
if (header.id != HEADER_ID) {
warning("ArjFile::readHeader(): Bad header ID (%x)", header.id);
@@ -199,7 +207,7 @@ ArjHeader *ArjFile::readHeader() {
header.flags = readS.readByte();
header.method = readS.readByte();
header.fileType = readS.readByte();
- (void)readS.readByte();
+ (void)readS.readByte(); // password_modifier
header.timeStamp = readS.readUint32LE();
header.compSize = readS.readSint32LE();
header.origSize = readS.readSint32LE();
@@ -208,20 +216,20 @@ ArjHeader *ArjFile::readHeader() {
header.fileMode = readS.readUint16LE();
header.hostData = readS.readUint16LE();
+ // static int check_file_size()
if (header.origSize < 0 || header.compSize < 0) {
warning("ArjFile::readHeader(): Wrong file size");
return NULL;
}
- strncpy(header.filename, (const char *)&headData[header.firstHdrSize], FNAME_MAX);
-
- strncpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], COMMENT_MAX);
+ strncpy(header.filename, (const char *)&headData[header.firstHdrSize], ARJ_FILENAME_MAX);
- /* if extheadersize == 0 then no CRC */
- /* otherwise read extheader data and read 4 bytes for CRC */
+ strncpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], ARJ_COMMENT_MAX);
- while ((header.extHeaderSize = _currArchive.readUint16LE()) != 0)
- _currArchive.seek((long)(header.extHeaderSize + 4), SEEK_CUR);
+ // Process extended headers, if any
+ uint16 extHeaderSize;
+ while ((extHeaderSize = _currArchive.readUint16LE()) != 0)
+ _currArchive.seek((long)(extHeaderSize + 4), SEEK_CUR);
header.pos = _currArchive.pos();
@@ -256,6 +264,11 @@ bool ArjFile::open(const Common::String &filename) {
_compsize = hdr->compSize;
_origsize = hdr->origSize;
+ // FIXME: This hotfix prevents Drascula from leaking memory.
+ // As far as sanity checks go this is not bad, but the engine should be fixed.
+ if (_uncompressedData)
+ free(_uncompressedData);
+
_uncompressedData = (byte *)malloc(_origsize);
_outstream = new MemoryWriteStream(_uncompressedData, _origsize);
@@ -315,53 +328,70 @@ bool ArjFile::eos() {
return _uncompressed->eos();
}
-uint32 ArjFile::pos() {
+int32 ArjFile::pos() {
return _uncompressed->pos();
}
-uint32 ArjFile::size() {
+int32 ArjFile::size() {
return _uncompressed->size();
}
-void ArjFile::seek(int32 offset, int whence) {
- _uncompressed->seek(offset, whence);
+bool ArjFile::seek(int32 offset, int whence) {
+ return _uncompressed->seek(offset, whence);
}
+//
+// Source for init_getbits: arj_file.c (decode_start_stub)
+//
+
void ArjFile::init_getbits() {
_bitbuf = 0;
- _subbitbuf = 0;
+ _bytebuf = 0;
_bitcount = 0;
- fillbuf(2 * CHAR_BIT);
+ fillbuf(ARJ_CHAR_BIT * 2);
}
-void ArjFile::fillbuf(int n) { // Shift bitbuf n bits left, read n bits
- _bitbuf = (_bitbuf << n) & 0xFFFF; /* lose the first n bits */
- while (n > _bitcount) {
- _bitbuf |= _subbitbuf << (n -= _bitcount);
- if (_compsize != 0) {
+//
+// Source for fillbuf, getbits: decode.c
+//
+
+void ArjFile::fillbuf(int n) {
+ while (_bitcount < n) {
+ _bitbuf = (_bitbuf << _bitcount) | (_bytebuf >> (8 - _bitcount));
+ n -= _bitcount;
+ if (_compsize > 0) {
_compsize--;
- _subbitbuf = _compressed->readByte();
- } else
- _subbitbuf = 0;
- _bitcount = CHAR_BIT;
+ _bytebuf = _compressed->readByte();
+ } else {
+ _bytebuf = 0;
+ }
+ _bitcount = 8;
}
- _bitbuf |= _subbitbuf >> (_bitcount -= n);
+ _bitcount -= n;
+ _bitbuf = ( _bitbuf << n) | (_bytebuf >> (8-n));
+ _bytebuf <<= n;
}
+// Reads a series of bits into the input buffer */
uint16 ArjFile::getbits(int n) {
- uint16 x;
+ uint16 rc;
- x = _bitbuf >> (2 * CHAR_BIT - n);
+ rc = _bitbuf >> (ARJ_CODE_BIT - n);
fillbuf(n);
- return x;
+ return rc;
}
-/* Huffman decode routines */
+//
+// Huffman decode routines
+// Source: decode.c
+//
+// Creates a table for decoding
void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize) {
- uint16 count[17], weight[17], start[18], *p;
+ uint16 count[17], weight[17], start[18];
+ uint16 *p;
uint i, k, len, ch, jutbits, avail, nextcode, mask;
for (i = 1; i <= 16; i++)
@@ -410,7 +440,8 @@ void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table,
while (i != 0) {
if (*p == 0) {
_right[avail] = _left[avail] = 0;
- *p = avail++;
+ *p = avail;
+ avail++;
}
if (k & mask)
p = &_right[*p];
@@ -425,6 +456,7 @@ void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table,
}
}
+// Reads length of data pending
void ArjFile::read_pt_len(int nn, int nbit, int i_special) {
int i, n;
int16 c;
@@ -440,9 +472,9 @@ void ArjFile::read_pt_len(int nn, int nbit, int i_special) {
} else {
i = 0;
while (i < n) {
- c = _bitbuf >> (13);
+ c = _bitbuf >> 13;
if (c == 7) {
- mask = 1 << (12);
+ mask = 1 << 12;
while (mask & _bitbuf) {
mask >>= 1;
c++;
@@ -458,10 +490,11 @@ void ArjFile::read_pt_len(int nn, int nbit, int i_special) {
}
while (i < nn)
_pt_len[i++] = 0;
- make_table(nn, _pt_len, 8, _pt_table, PTABLESIZE); // replaced sizeof
+ make_table(nn, _pt_len, 8, _pt_table, ARJ_PTABLESIZE);
}
}
+// Reads a character table
void ArjFile::read_c_len() {
int16 i, c, n;
uint16 mask;
@@ -469,82 +502,87 @@ void ArjFile::read_c_len() {
n = getbits(CBIT);
if (n == 0) {
c = getbits(CBIT);
- for (i = 0; i < NC; i++)
+ for (i = 0; i < ARJ_NC; i++)
_c_len[i] = 0;
- for (i = 0; i < CTABLESIZE; i++)
+ for (i = 0; i < ARJ_CTABLESIZE; i++)
_c_table[i] = c;
} else {
i = 0;
while (i < n) {
c = _pt_table[_bitbuf >> (8)];
- if (c >= NT) {
- mask = 1 << (7);
+ if (c >= ARJ_NT) {
+ mask = 1 << 7;
do {
if (_bitbuf & mask)
c = _right[c];
else
c = _left[c];
mask >>= 1;
- } while (c >= NT);
+ } while (c >= ARJ_NT);
}
fillbuf((int)(_pt_len[c]));
if (c <= 2) {
if (c == 0)
c = 1;
- else if (c == 1)
- c = getbits(4) + 3;
- else
- c = getbits(CBIT) + 20;
+ else if (c == 1) {
+ c = getbits(4);
+ c += 3;
+ } else {
+ c = getbits(CBIT);
+ c += 20;
+ }
while (--c >= 0)
_c_len[i++] = 0;
}
else
_c_len[i++] = (byte)(c - 2);
}
- while (i < NC)
+ while (i < ARJ_NC)
_c_len[i++] = 0;
- make_table(NC, _c_len, 12, _c_table, CTABLESIZE); // replaced sizeof
+ make_table(ARJ_NC, _c_len, 12, _c_table, ARJ_CTABLESIZE);
}
}
+// Decodes a single character
uint16 ArjFile::decode_c() {
uint16 j, mask;
if (_blocksize == 0) {
- _blocksize = getbits(16);
- read_pt_len(NT, TBIT, 3);
+ _blocksize = getbits(ARJ_CODE_BIT);
+ read_pt_len(ARJ_NT, TBIT, 3);
read_c_len();
- read_pt_len(NP, PBIT, -1);
+ read_pt_len(ARJ_NP, PBIT, -1);
}
_blocksize--;
j = _c_table[_bitbuf >> 4];
- if (j >= NC) {
- mask = 1 << (3);
+ if (j >= ARJ_NC) {
+ mask = 1 << 3;
do {
if (_bitbuf & mask)
j = _right[j];
else
j = _left[j];
mask >>= 1;
- } while (j >= NC);
+ } while (j >= ARJ_NC);
}
fillbuf((int)(_c_len[j]));
return j;
}
+// Decodes a control character
uint16 ArjFile::decode_p() {
uint16 j, mask;
- j = _pt_table[_bitbuf >> (8)];
- if (j >= NP) {
- mask = 1 << (7);
+ j = _pt_table[_bitbuf >> 8];
+ if (j >= ARJ_NP) {
+ mask = 1 << 7;
do {
if (_bitbuf & mask)
j = _right[j];
else
j = _left[j];
mask >>= 1;
- } while (j >= NP);
+ } while (j >= ARJ_NP);
}
fillbuf((int)(_pt_len[j]));
if (j != 0) {
@@ -554,63 +592,59 @@ uint16 ArjFile::decode_p() {
return j;
}
+// Initializes memory for decoding
void ArjFile::decode_start() {
_blocksize = 0;
init_getbits();
}
+// Decodes the entire file
void ArjFile::decode() {
int16 i;
- int16 j;
- int16 c;
int16 r;
+ int16 c;
+ int16 j;
int32 count;
decode_start();
- count = 0;
+ count = _origsize;
r = 0;
- while (count < _origsize) {
+ while (count > 0) {
if ((c = decode_c()) <= ARJ_UCHAR_MAX) {
- _text[r] = (byte) c;
- count++;
- if (++r >= DDICSIZ) {
+ _ntext[r] = (byte) c;
+ count--;
+ if (++r >= ARJ_DICSIZ) {
r = 0;
- _outstream->write(_text, DDICSIZ);
+ _outstream->write(_ntext, ARJ_DICSIZ);
}
} else {
- j = c - (ARJ_UCHAR_MAX + 1 - THRESHOLD);
- count += j;
- i = decode_p();
- if ((i = r - i - 1) < 0)
- i += DDICSIZ;
- if (r > i && r < DDICSIZ - MAXMATCH - 1) {
+ j = c - (ARJ_UCHAR_MAX + 1 - ARJ_THRESHOLD);
+ count -= j;
+ i = r - decode_p() - 1;
+ if (i < 0)
+ i += ARJ_DICSIZ;
+ if (r > i && r < ARJ_DICSIZ - ARJ_MAXMATCH - 1) {
while (--j >= 0)
- _text[r++] = _text[i++];
+ _ntext[r++] = _ntext[i++];
} else {
while (--j >= 0) {
- _text[r] = _text[i];
- if (++r >= DDICSIZ) {
+ _ntext[r] = _ntext[i];
+ if (++r >= ARJ_DICSIZ) {
r = 0;
- _outstream->write(_text, DDICSIZ);
+ _outstream->write(_ntext, ARJ_DICSIZ);
}
- if (++i >= DDICSIZ)
+ if (++i >= ARJ_DICSIZ)
i = 0;
}
}
}
}
- if (r != 0)
- _outstream->write(_text, r);
+ if (r > 0)
+ _outstream->write(_ntext, r);
}
-/* Macros */
-
-#define BFIL {_getbuf|=_bitbuf>>_getlen;fillbuf(CODE_BIT-_getlen);_getlen=CODE_BIT;}
-#define GETBIT(c) {if(_getlen<=0)BFIL c=(_getbuf&0x8000)!=0;_getbuf<<=1;_getlen--;}
-#define BPUL(l) {_getbuf<<=l;_getlen-=l;}
-#define GETBITS(c,l) {if(_getlen<l)BFIL c=(uint16)_getbuf>>(CODE_BIT-l);BPUL(l)}
-
+// Backward pointer decoding
int16 ArjFile::decode_ptr() {
int16 c = 0;
int16 width;
@@ -618,20 +652,21 @@ int16 ArjFile::decode_ptr() {
int16 pwr;
plus = 0;
- pwr = 1 << (STRTP);
- for (width = (STRTP); width < (STOPP); width++) {
- GETBIT(c);
+ pwr = 1 << 9;
+ for (width = 9; width < 13; width++) {
+ c = getbits(1);
if (c == 0)
break;
plus += pwr;
pwr <<= 1;
}
if (width != 0)
- GETBITS(c, width);
+ c = getbits(width);
c += plus;
return c;
}
+// Reference length decoding
int16 ArjFile::decode_len() {
int16 c = 0;
int16 width;
@@ -639,62 +674,60 @@ int16 ArjFile::decode_len() {
int16 pwr;
plus = 0;
- pwr = 1 << (STRTL);
- for (width = (STRTL); width < (STOPL); width++) {
- GETBIT(c);
+ pwr = 1;
+ for (width = 0; width < 7; width++) {
+ c = getbits(1);
if (c == 0)
break;
plus += pwr;
pwr <<= 1;
}
if (width != 0)
- GETBITS(c, width);
+ c = getbits(width);
c += plus;
return c;
}
+// Decodes the entire file, using method 4
void ArjFile::decode_f() {
int16 i;
int16 j;
int16 c;
int16 r;
- int16 pos1;
- int32 count;
+ uint32 ncount;
init_getbits();
+ ncount = 0;
_getlen = _getbuf = 0;
- count = 0;
r = 0;
- while (count < _origsize) {
+ while (ncount < (uint32)_origsize) {
c = decode_len();
if (c == 0) {
- GETBITS(c, CHAR_BIT);
- _text[r] = (byte)c;
- count++;
- if (++r >= DDICSIZ) {
+ ncount++;
+ _ntext[r] = (byte)getbits(8);
+ if (++r >= ARJ_FDICSIZ) {
r = 0;
- _outstream->write(_text, DDICSIZ);
+ _outstream->write(_ntext, ARJ_FDICSIZ);
}
} else {
- j = c - 1 + THRESHOLD;
- count += j;
- pos1 = decode_ptr();
- if ((i = r - pos1 - 1) < 0)
- i += DDICSIZ;
+ j = c - 1 + ARJ_THRESHOLD;
+ ncount += j;
+ if ((i = r - decode_ptr() - 1) < 0)
+ i += ARJ_FDICSIZ;
while (j-- > 0) {
- _text[r] = _text[i];
- if (++r >= DDICSIZ) {
+ _ntext[r] = _ntext[i];
+ if (++r >= ARJ_FDICSIZ) {
r = 0;
- _outstream->write(_text, DDICSIZ);
+ _outstream->write(_ntext, ARJ_FDICSIZ);
}
- if (++i >= DDICSIZ)
+ if (++i >= ARJ_FDICSIZ)
i = 0;
}
}
}
if (r != 0)
- _outstream->write(_text, r);
+ _outstream->write(_ntext, r);
}
diff --git a/common/unarj.h b/common/unarj.h
index c8965968f6..52e0d13948 100644
--- a/common/unarj.h
+++ b/common/unarj.h
@@ -31,46 +31,31 @@
namespace Common {
-#define HEADER_ID 0xEA60
-#define HEADER_ID_HI 0xEA
-#define HEADER_ID_LO 0x60
-#define FIRST_HDR_SIZE 30
-#define FIRST_HDR_SIZE_V 34
-#define COMMENT_MAX 2048
-#define FNAME_MAX 512
-#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX)
-#define CRC_MASK 0xFFFFFFFFL
-#define MAXSFX 25000L
-
-#define CODE_BIT 16
-#define CHAR_BIT 8
-#define ARJ_UCHAR_MAX 255 // UCHAR_MAX is defined in limits.h in MSVC
-#define THRESHOLD 3
-#define DDICSIZ 26624
-#define MAXDICBIT 16
-#define MATCHBIT 8
-#define MAXMATCH 256
-#define NC (ARJ_UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
-#define NP (MAXDICBIT + 1)
-#define CBIT 9
-#define NT (CODE_BIT + 3)
-#define PBIT 5
-#define TBIT 5
-
-#if NT > NP
-#define NPT NT
+#define ARJ_UCHAR_MAX 255
+#define ARJ_CHAR_BIT 8
+
+#define ARJ_COMMENT_MAX 2048
+#define ARJ_FILENAME_MAX 512
+
+#define ARJ_CODE_BIT 16
+#define ARJ_THRESHOLD 3
+#define ARJ_DICSIZ 26624
+#define ARJ_FDICSIZ ARJ_DICSIZ
+#define ARJ_MAXDICBIT 16
+#define ARJ_MAXMATCH 256
+#define ARJ_NC (ARJ_UCHAR_MAX + ARJ_MAXMATCH + 2 - ARJ_THRESHOLD)
+#define ARJ_NP (ARJ_MAXDICBIT + 1)
+#define ARJ_NT (ARJ_CODE_BIT + 3)
+
+#if ARJ_NT > ARJ_NP
+#define ARJ_NPT ARJ_NT
#else
-#define NPT NP
+#define ARJ_NPT ARJ_NP
#endif
-#define CTABLESIZE 4096
-#define PTABLESIZE 256
+#define ARJ_CTABLESIZE 4096
+#define ARJ_PTABLESIZE 256
-#define STRTP 9
-#define STOPP 13
-
-#define STRTL 0
-#define STOPL 7
struct ArjHeader {
int32 pos;
@@ -92,9 +77,8 @@ struct ArjHeader {
uint16 entryPos;
uint16 fileMode;
uint16 hostData;
- char filename[FNAME_MAX];
- char comment[COMMENT_MAX];
- uint16 extHeaderSize;
+ char filename[ARJ_FILENAME_MAX];
+ char comment[ARJ_COMMENT_MAX];
uint32 headerCrc;
};
@@ -115,9 +99,9 @@ public:
uint32 read(void *dataPtr, uint32 dataSize);
bool eos();
- uint32 pos();
- uint32 size();
- void seek(int32 offset, int whence = SEEK_SET);
+ int32 pos();
+ int32 size();
+ bool seek(int32 offset, int whence = SEEK_SET);
bool isOpen() { return _isOpen; }
private:
@@ -143,6 +127,7 @@ private:
void decode_f();
uint16 _bitbuf;
+ uint16 _bytebuf;
int32 _compsize;
int32 _origsize;
byte _subbitbuf;
@@ -163,18 +148,18 @@ private:
int16 decode_len(void);
private:
- byte _text[DDICSIZ];
+ byte _ntext[ARJ_FDICSIZ];
int16 _getlen;
int16 _getbuf;
- uint16 _left[2 * NC - 1];
- uint16 _right[2 * NC - 1];
- byte _c_len[NC];
- byte _pt_len[NPT];
+ uint16 _left[2 * ARJ_NC - 1];
+ uint16 _right[2 * ARJ_NC - 1];
+ byte _c_len[ARJ_NC];
+ byte _pt_len[ARJ_NPT];
- uint16 _c_table[CTABLESIZE];
- uint16 _pt_table[PTABLESIZE];
+ uint16 _c_table[ARJ_CTABLESIZE];
+ uint16 _pt_table[ARJ_PTABLESIZE];
uint16 _blocksize;
diff --git a/common/unzip.cpp b/common/unzip.cpp
index 93fb60f41c..054200e7a2 100644
--- a/common/unzip.cpp
+++ b/common/unzip.cpp
@@ -28,14 +28,51 @@
Read unzip.h for more info
*/
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 0.15 beta, Mar 19th, 1998,
+
+ Copyright (C) 1998 Gilles Vollant
+
+ This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
+ WinZip, InfoZip tools and compatible.
+ Encryption and multi volume ZipFile (span) are not supported.
+ Old compressions used by old PKZip 1.x are not supported
+
+ THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
+ CAN CHANGE IN FUTURE VERSION !!
+ I WAIT FEEDBACK at mail info@winimage.com
+ Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+
+*/
+/* for more info about .ZIP format, see
+ ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
+ PkWare has also a specification at :
+ ftp://ftp.pkware.com/probdesc.zip */
+
+
#include "common/scummsys.h"
#ifdef USE_ZLIB
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#ifdef __SYMBIAN32__
#include <zlib\zlib.h>
#else
@@ -45,24 +82,213 @@
#include "common/unzip.h"
#include "common/file.h"
-#ifdef STDC
-# include <stddef.h>
-# include <string.h>
-# include <stdlib.h>
-#endif
-#ifdef NO_ERRNO_H
- extern int errno;
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
#else
-# include <errno.h>
+typedef voidp unzFile;
#endif
-#ifndef local
-# define local static
-#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct {
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct {
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct {
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+int unzStringFileNameCompare(const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity);
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+unzFile unzOpen(const char *path);
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
+ "zlib/zlib111.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+
+int unzClose(unzFile file);
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+
+int unzGetGlobalInfo(unzFile file,
+ unz_global_info *pglobal_info);
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf);
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+int unzGoToFirstFile(unzFile file);
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+int unzGoToNextFile(unzFile file);
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity);
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+int unzGetCurrentFileInfo(unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize);
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+int unzOpenCurrentFile(unzFile file);
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+int unzCloseCurrentFile(unzFile file);
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+
+int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+z_off_t unztell(unzFile file);
+/*
+ Give the current position in uncompressed data
+*/
+
+int unzeof(unzFile file);
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len);
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+ if buf==NULL, it return the size of the local extra field
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
!defined(CASESENSITIVITYDEFAULT_NO)
@@ -78,45 +304,22 @@
#define UNZ_MAXFILENAMEINZIP (256)
#endif
-#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
-#endif
-#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
-#endif
-
#define SIZECENTRALDIRITEM (0x2e)
#define SIZEZIPLOCALHEADER (0x1e)
-/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
-
-#ifndef SEEK_CUR
-#define SEEK_CUR 1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END 2
-#endif
-
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#endif
-
const char unz_copyright[] =
" unzip 0.15 Copyright 1998 Gilles Vollant ";
/* unz_file_info_interntal contain internal info about a file in zipfile*/
-typedef struct unz_file_info_internal_s
-{
+typedef struct {
uLong offset_curfile;/* relative offset of local header 4 bytes */
} unz_file_info_internal;
/* file_in_zip_read_info_s contain internal information about a file in zipfile,
when reading and decompress it */
-typedef struct
-{
+typedef struct {
char *read_buffer; /* internal buffer for compressed data */
z_stream stream; /* zLib stream structure for inflate */
@@ -139,8 +342,7 @@ typedef struct
/* unz_s contain internal information about the zipfile
*/
-typedef struct
-{
+typedef struct {
Common::File file; /* io structore of the zipfile */
unz_global_info gi; /* public global information */
uLong byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/
@@ -166,14 +368,11 @@ typedef struct
*/
-/*local int unzlocal_getByte(Common::File &fin, int *pi)
-{
+/*static int unzlocal_getByte(Common::File &fin, int *pi) {
unsigned char c = fin.readByte();
*pi = (int)c;
return UNZ_OK;
- }
- else
- {
+ } else {
if (fin.ioFailed())
return UNZ_ERRNO;
else
@@ -185,37 +384,14 @@ typedef struct
/* ===========================================================================
Reads a long in LSB order from the given gz_stream. Sets
*/
-local int unzlocal_getShort (Common::File &fin, uLong *pX)
-{
+static int unzlocal_getShort(Common::File &fin, uLong *pX) {
*pX = fin.readUint16LE();
- return UNZ_OK;
+ return fin.ioFailed() ? UNZ_ERRNO : UNZ_OK;
}
-local int unzlocal_getLong (Common::File &fin, uLong *pX)
-{
+static int unzlocal_getLong(Common::File &fin, uLong *pX) {
*pX = fin.readUint32LE();
- return UNZ_OK;
-}
-
-/* My own strcmpi / strcasecmp */
-local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) {
- for (;;)
- {
- char c1=*(fileName1++);
- char c2=*(fileName2++);
- if ((c1>='a') && (c1<='z'))
- c1 -= 0x20;
- if ((c2>='a') && (c2<='z'))
- c2 -= 0x20;
- if (c1=='\0')
- return ((c2=='\0') ? 0 : -1);
- if (c2=='\0')
- return 1;
- if (c1<c2)
- return -1;
- if (c1>c2)
- return 1;
- }
+ return fin.ioFailed() ? UNZ_ERRNO : UNZ_OK;
}
@@ -225,10 +401,6 @@ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fil
#define CASESENSITIVITYDEFAULTVALUE 1
#endif
-#ifndef STRCMPCASENOSENTIVEFUNCTION
-#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
-#endif
-
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
@@ -238,15 +410,14 @@ local int strcmpcasenosensitive_internal (const char* fileName1, const char* fil
(like 1 on Unix, 2 on Windows)
*/
-extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity)
-{
+int unzStringFileNameCompare(const char* fileName1, const char* fileName2, int iCaseSensitivity) {
if (iCaseSensitivity==0)
iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
if (iCaseSensitivity==1)
return strcmp(fileName1,fileName2);
- return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+ return scumm_stricmp(fileName1,fileName2);
}
#define BUFREADCOMMENT (0x400)
@@ -255,8 +426,7 @@ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, const char*
Locate the Central directory of a zipfile (at the end, just before
the global comment)
*/
-local uLong unzlocal_SearchCentralDir(Common::File &fin)
-{
+static uLong unzlocal_SearchCentralDir(Common::File &fin) {
unsigned char* buf;
uLong uSizeFile;
uLong uBackRead;
@@ -270,13 +440,12 @@ local uLong unzlocal_SearchCentralDir(Common::File &fin)
if (uMaxBack>uSizeFile)
uMaxBack = uSizeFile;
- buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ buf = (unsigned char*)malloc(BUFREADCOMMENT+4);
if (buf==NULL)
return 0;
uBackRead = 4;
- while (uBackRead<uMaxBack)
- {
+ while (uBackRead<uMaxBack) {
uLong uReadSize,uReadPos ;
int i;
if (uBackRead+BUFREADCOMMENT>uMaxBack)
@@ -305,7 +474,7 @@ local uLong unzlocal_SearchCentralDir(Common::File &fin)
if (uPosFound!=0)
break;
}
- TRYFREE(buf);
+ free(buf);
return uPosFound;
}
@@ -318,8 +487,7 @@ local uLong unzlocal_SearchCentralDir(Common::File &fin)
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
-extern unzFile ZEXPORT unzOpen (const char *path)
-{
+unzFile unzOpen(const char *path) {
unz_s *us = new unz_s;
uLong central_pos,uL;
@@ -408,8 +576,7 @@ extern unzFile ZEXPORT unzOpen (const char *path)
If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzClose (unzFile file)
-{
+int unzClose(unzFile file) {
unz_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
@@ -428,8 +595,7 @@ extern int ZEXPORT unzClose (unzFile file)
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
-extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info)
-{
+int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info) {
unz_s* s;
if (file==NULL)
return UNZ_PARAMERROR;
@@ -442,8 +608,7 @@ extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info
/*
Translate date/time from Dos format to tm_unz (readable more easilty)
*/
-local void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm)
-{
+static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) {
uLong uDate;
uDate = (uLong)(ulDosDate>>16);
ptm->tm_mday = (uInt)(uDate&0x1f) ;
@@ -458,7 +623,7 @@ local void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm)
/*
Get Info about the current file in the zipfile, with internal only info
*/
-local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
+static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
unz_file_info *pfile_info,
unz_file_info_internal
*pfile_info_internal,
@@ -467,9 +632,9 @@ local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
- uLong commentBufferSize));
+ uLong commentBufferSize);
-local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
+static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
unz_file_info *pfile_info,
unz_file_info_internal *pfile_info_internal,
char *szFileName, uLong fileNameBufferSize,
@@ -492,8 +657,7 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
/* we check the magic */
- if (err==UNZ_OK)
- {
+ if (err==UNZ_OK) {
if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
err=UNZ_ERRNO;
else if (uMagic!=0x02014b50)
@@ -548,15 +712,12 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
err=UNZ_ERRNO;
lSeek+=file_info.size_filename;
- if ((err==UNZ_OK) && (szFileName!=NULL))
- {
+ if ((err==UNZ_OK) && (szFileName!=NULL)) {
uLong uSizeRead ;
- if (file_info.size_filename<fileNameBufferSize)
- {
+ if (file_info.size_filename<fileNameBufferSize) {
*(szFileName+file_info.size_filename)='\0';
uSizeRead = file_info.size_filename;
- }
- else
+ } else
uSizeRead = fileNameBufferSize;
if ((file_info.size_filename>0) && (fileNameBufferSize>0))
@@ -566,16 +727,14 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
}
- if ((err==UNZ_OK) && (extraField!=NULL))
- {
+ if ((err==UNZ_OK) && (extraField!=NULL)) {
uLong uSizeRead ;
if (file_info.size_file_extra<extraFieldBufferSize)
uSizeRead = file_info.size_file_extra;
else
uSizeRead = extraFieldBufferSize;
- if (lSeek!=0)
- {
+ if (lSeek!=0) {
s->file.seek(lSeek, SEEK_CUR);
if (s->file.ioFailed())
lSeek=0;
@@ -591,19 +750,15 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
lSeek+=file_info.size_file_extra;
- if ((err==UNZ_OK) && (szComment!=NULL))
- {
+ if ((err==UNZ_OK) && (szComment!=NULL)) {
uLong uSizeRead ;
- if (file_info.size_file_comment<commentBufferSize)
- {
+ if (file_info.size_file_comment<commentBufferSize) {
*(szComment+file_info.size_file_comment)='\0';
uSizeRead = file_info.size_file_comment;
- }
- else
+ } else
uSizeRead = commentBufferSize;
- if (lSeek!=0)
- {
+ if (lSeek!=0) {
s->file.seek(lSeek, SEEK_CUR);
if (s->file.ioFailed())
lSeek=0;
@@ -614,8 +769,7 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
if (s->file.read(szComment,(uInt)uSizeRead)!=uSizeRead)
err=UNZ_ERRNO;
lSeek+=file_info.size_file_comment - uSizeRead;
- }
- else
+ } else
lSeek+=file_info.size_file_comment;
if ((err==UNZ_OK) && (pfile_info!=NULL))
@@ -634,7 +788,7 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file,
No preparation of the structure is needed
return UNZ_OK if there is no problem.
*/
-extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
+int unzGetCurrentFileInfo(unzFile file,
unz_file_info *pfile_info,
char *szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize,
@@ -650,8 +804,7 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
-extern int ZEXPORT unzGoToFirstFile (unzFile file)
-{
+int unzGoToFirstFile(unzFile file) {
int err=UNZ_OK;
unz_s* s;
if (file==NULL)
@@ -672,8 +825,7 @@ extern int ZEXPORT unzGoToFirstFile (unzFile file)
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
-extern int ZEXPORT unzGoToNextFile (unzFile file)
-{
+int unzGoToNextFile(unzFile file) {
unz_s* s;
int err;
@@ -704,8 +856,7 @@ extern int ZEXPORT unzGoToNextFile (unzFile file)
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
-extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
-{
+int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
unz_s* s;
int err;
@@ -729,8 +880,7 @@ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCas
err = unzGoToFirstFile(file);
- while (err == UNZ_OK)
- {
+ while (err == UNZ_OK) {
char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
unzGetCurrentFileInfo(file,NULL,
szCurrentFileName,sizeof(szCurrentFileName)-1,
@@ -754,10 +904,9 @@ extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCas
store in *piSizeVar the size of extra info in local header
(filename and size of extra field data)
*/
-local int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar,
+static int unzlocal_CheckCurrentFileCoherencyHeader(unz_s* s, uInt* piSizeVar,
uLong *poffset_local_extrafield,
- uInt *psize_local_extrafield)
-{
+ uInt *psize_local_extrafield) {
uLong uMagic,uData,uFlags;
uLong size_filename;
uLong size_extra_field;
@@ -773,8 +922,7 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar,
return UNZ_ERRNO;
- if (err==UNZ_OK)
- {
+ if (err==UNZ_OK) {
if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
err=UNZ_ERRNO;
else if (uMagic!=0x04034b50)
@@ -843,8 +991,7 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar,
Open for reading data the current file in the zipfile.
If there is no error and the file is opened, the return value is UNZ_OK.
*/
-extern int ZEXPORT unzOpenCurrentFile (unzFile file)
-{
+int unzOpenCurrentFile (unzFile file) {
int err=UNZ_OK;
int Store;
uInt iSizeVar;
@@ -866,19 +1013,19 @@ extern int ZEXPORT unzOpenCurrentFile (unzFile file)
&offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
return UNZ_BADZIPFILE;
- pfile_in_zip_read_info = (file_in_zip_read_info_s*) ALLOC(sizeof(file_in_zip_read_info_s));
+ pfile_in_zip_read_info = (file_in_zip_read_info_s*) malloc(sizeof(file_in_zip_read_info_s));
if (pfile_in_zip_read_info==NULL)
return UNZ_INTERNALERROR;
- pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE);
pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
pfile_in_zip_read_info->pos_local_extrafield=0;
if (pfile_in_zip_read_info->read_buffer==NULL)
{
- TRYFREE(pfile_in_zip_read_info);
+ free(pfile_in_zip_read_info);
return UNZ_INTERNALERROR;
}
@@ -938,8 +1085,7 @@ extern int ZEXPORT unzOpenCurrentFile (unzFile file)
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
-extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
-{
+int unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
int err=UNZ_OK;
uInt iRead = 0;
unz_s* s;
@@ -1051,8 +1197,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
/*
Give the current position in uncompressed data
*/
-extern z_off_t ZEXPORT unztell (unzFile file)
-{
+z_off_t unztell(unzFile file) {
unz_s* s;
file_in_zip_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
@@ -1070,8 +1215,7 @@ extern z_off_t ZEXPORT unztell (unzFile file)
/*
return 1 if the end of file was reached, 0 elsewhere
*/
-extern int ZEXPORT unzeof (unzFile file)
-{
+int unzeof(unzFile file) {
unz_s* s;
file_in_zip_read_info_s* pfile_in_zip_read_info;
if (file==NULL)
@@ -1102,8 +1246,7 @@ extern int ZEXPORT unzeof (unzFile file)
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
-extern int ZEXPORT unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len)
-{
+int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {
unz_s* s;
file_in_zip_read_info_s* pfile_in_zip_read_info;
uInt read_now;
@@ -1146,8 +1289,7 @@ extern int ZEXPORT unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len)
Close the file in zip opened with unzipOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
-extern int ZEXPORT unzCloseCurrentFile (unzFile file)
-{
+int unzCloseCurrentFile(unzFile file) {
int err=UNZ_OK;
unz_s* s;
@@ -1167,13 +1309,13 @@ extern int ZEXPORT unzCloseCurrentFile (unzFile file)
}
- TRYFREE(pfile_in_zip_read_info->read_buffer);
+ free(pfile_in_zip_read_info->read_buffer);
pfile_in_zip_read_info->read_buffer = NULL;
if (pfile_in_zip_read_info->stream_initialised)
inflateEnd(&pfile_in_zip_read_info->stream);
pfile_in_zip_read_info->stream_initialised = 0;
- TRYFREE(pfile_in_zip_read_info);
+ free(pfile_in_zip_read_info);
s->pfile_in_zip_read=NULL;
@@ -1186,8 +1328,7 @@ extern int ZEXPORT unzCloseCurrentFile (unzFile file)
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
-extern int ZEXPORT unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf)
-{
+int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf) {
unz_s* s;
uLong uReadThis ;
if (file==NULL)
@@ -1213,4 +1354,92 @@ extern int ZEXPORT unzGetGlobalComment (unzFile file, char *szComment, uLong uSi
return (int)uReadThis;
}
+
+namespace Common {
+
+
+/*
+class ZipArchiveMember : public ArchiveMember {
+ unzFile _zipFile;
+
+public:
+ ZipArchiveMember(FilesystemNode &node) : _node(node) {
+ }
+
+ String getName() const {
+ ...
+ }
+
+ SeekableReadStream *open() {
+ ...
+ }
+};
+*/
+
+ZipArchive::ZipArchive(const Common::String &name) {
+ _zipFile = unzOpen(name.c_str());
+}
+
+ZipArchive::~ZipArchive() {
+ unzClose(_zipFile);
+}
+
+bool ZipArchive::isOpen() const {
+ return _zipFile != 0;
+}
+
+bool ZipArchive::hasFile(const Common::String &name) {
+ return (_zipFile && unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK);
+}
+
+int ZipArchive::getAllNames(Common::StringList &list) {
+ return 0;
+}
+
+/*
+int ZipArchive::listMembers(Common::ArchiveMemberList &list) {
+ if (!_zipFile)
+ return 0;
+
+ int matches = 0;
+ int err = unzGoToFirstFile(_zipFile);
+
+ while (err == UNZ_OK) {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ unzGetCurrentFileInfo(_zipFile, NULL,
+ szCurrentFileName, sizeof(szCurrentFileName)-1,
+ NULL, 0, NULL, 0);
+
+ szCurrentFileName
+ matches++;
+ err = unzGoToNextFile(file);
+ }
+ return 0;
+}
+*/
+
+Common::SeekableReadStream *ZipArchive::openFile(const Common::String &name) {
+ if (!_zipFile)
+ return 0;
+
+ unzLocateFile(_zipFile, name.c_str(), 2);
+
+ unz_file_info fileInfo;
+ unzOpenCurrentFile(_zipFile);
+ unzGetCurrentFileInfo(_zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+ byte *buffer = (byte *)calloc(fileInfo.uncompressed_size+1, 1);
+ assert(buffer);
+ unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size);
+ unzCloseCurrentFile(_zipFile);
+ return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, true);
+
+ // FIXME: instead of reading all into a memory stream, we could
+ // instead create a new ZipStream class. But then we have to be
+ // careful to handle the case where the client code opens multiple
+ // files in the archive and tries to use them indepenendtly.
+}
+
+} // End of namespace Common
+
+
#endif
diff --git a/common/unzip.h b/common/unzip.h
index 2d888fe5b1..93afd0b05b 100644
--- a/common/unzip.h
+++ b/common/unzip.h
@@ -22,286 +22,34 @@
* $Id$
*/
-/* unzip.h -- IO for uncompress .zip files using zlib
- Version 0.15 beta, Mar 19th, 1998,
-
- Copyright (C) 1998 Gilles Vollant
-
- This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
- WinZip, InfoZip tools and compatible.
- Encryption and multi volume ZipFile (span) are not supported.
- Old compressions used by old PKZip 1.x are not supported
-
- THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
- CAN CHANGE IN FUTURE VERSION !!
- I WAIT FEEDBACK at mail info@winimage.com
- Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
-
- Condition of use and distribution are the same than zlib :
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
-
-*/
-/* for more info about .ZIP format, see
- ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
- PkWare has also a specification at :
- ftp://ftp.pkware.com/probdesc.zip */
-
-#ifndef _unz_H
-#define _unz_H
-
-#include "common/scummsys.h"
+#ifndef COMMON_UNZIP_H
+#define COMMON_UNZIP_H
#ifdef USE_ZLIB
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __SYMBIAN32__
-#include <zlib\zlib.h>
-#else
-#include <zlib.h>
-#endif
-
-#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
-/* like the STRICT of WIN32, we define a pointer that cannot be converted
- from (void*) without cast */
-typedef struct TagunzFile__ { int unused; } unzFile__;
-typedef unzFile__ *unzFile;
-#else
-typedef voidp unzFile;
-#endif
-
-
-#define UNZ_OK (0)
-#define UNZ_END_OF_LIST_OF_FILE (-100)
-#define UNZ_ERRNO (Z_ERRNO)
-#define UNZ_EOF (0)
-#define UNZ_PARAMERROR (-102)
-#define UNZ_BADZIPFILE (-103)
-#define UNZ_INTERNALERROR (-104)
-#define UNZ_CRCERROR (-105)
-
-/* tm_unz contain date/time info */
-typedef struct tm_unz_s
-{
- uInt tm_sec; /* seconds after the minute - [0,59] */
- uInt tm_min; /* minutes after the hour - [0,59] */
- uInt tm_hour; /* hours since midnight - [0,23] */
- uInt tm_mday; /* day of the month - [1,31] */
- uInt tm_mon; /* months since January - [0,11] */
- uInt tm_year; /* years - [1980..2044] */
-} tm_unz;
-
-/* unz_global_info structure contain global data about the ZIPfile
- These data comes from the end of central dir */
-typedef struct unz_global_info_s
-{
- uLong number_entry; /* total number of entries in
- the central dir on this disk */
- uLong size_comment; /* size of the global comment of the zipfile */
-} unz_global_info;
-
-
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_info_s
-{
- uLong version; /* version made by 2 bytes */
- uLong version_needed; /* version needed to extract 2 bytes */
- uLong flag; /* general purpose bit flag 2 bytes */
- uLong compression_method; /* compression method 2 bytes */
- uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
- uLong crc; /* crc-32 4 bytes */
- uLong compressed_size; /* compressed size 4 bytes */
- uLong uncompressed_size; /* uncompressed size 4 bytes */
- uLong size_filename; /* filename length 2 bytes */
- uLong size_file_extra; /* extra field length 2 bytes */
- uLong size_file_comment; /* file comment length 2 bytes */
-
- uLong disk_num_start; /* disk number start 2 bytes */
- uLong internal_fa; /* internal file attributes 2 bytes */
- uLong external_fa; /* external file attributes 4 bytes */
-
- tm_unz tmu_date;
-} unz_file_info;
-
-extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
- const char* fileName2,
- int iCaseSensitivity));
-/*
- Compare two filename (fileName1,fileName2).
- If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
- If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
- or strcasecmp)
- If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
- (like 1 on Unix, 2 on Windows)
-*/
-
-
-extern unzFile ZEXPORT unzOpen OF((const char *path));
-/*
- Open a Zip file. path contain the full pathname (by example,
- on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
- "zlib/zlib111.zip".
- If the zipfile cannot be opened (file don't exist or in not valid), the
- return value is NULL.
- Else, the return value is a unzFile Handle, usable with other function
- of this unzip package.
-*/
-
-extern int ZEXPORT unzClose OF((unzFile file));
-/*
- Close a ZipFile opened with unzipOpen.
- If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
- these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
- return UNZ_OK if there is no problem. */
-
-extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
- unz_global_info *pglobal_info));
-/*
- Write info about the ZipFile in the *pglobal_info structure.
- No preparation of the structure is needed
- return UNZ_OK if there is no problem. */
-
-
-extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
- char *szComment,
- uLong uSizeBuf));
-/*
- Get the global comment string of the ZipFile, in the szComment buffer.
- uSizeBuf is the size of the szComment buffer.
- return the number of byte copied or an error code <0
-*/
-
-
-/***************************************************************************/
-/* Unzip package allow you browse the directory of the zipfile */
-
-extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
-/*
- Set the current file of the zipfile to the first file.
- return UNZ_OK if there is no problem
-*/
-
-extern int ZEXPORT unzGoToNextFile OF((unzFile file));
-/*
- Set the current file of the zipfile to the next file.
- return UNZ_OK if there is no problem
- return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
-*/
-
-extern int ZEXPORT unzLocateFile OF((unzFile file,
- const char *szFileName,
- int iCaseSensitivity));
-/*
- Try locate the file szFileName in the zipfile.
- For the iCaseSensitivity signification, see unzStringFileNameCompare
-
- return value :
- UNZ_OK if the file is found. It becomes the current file.
- UNZ_END_OF_LIST_OF_FILE if the file is not found
-*/
-
-
-extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
- unz_file_info *pfile_info,
- char *szFileName,
- uLong fileNameBufferSize,
- void *extraField,
- uLong extraFieldBufferSize,
- char *szComment,
- uLong commentBufferSize));
-/*
- Get Info about the current file
- if pfile_info!=NULL, the *pfile_info structure will contain somes info about
- the current file
- if szFileName!=NULL, the filemane string will be copied in szFileName
- (fileNameBufferSize is the size of the buffer)
- if extraField!=NULL, the extra field information will be copied in extraField
- (extraFieldBufferSize is the size of the buffer).
- This is the Central-header version of the extra field
- if szComment!=NULL, the comment string of the file will be copied in szComment
- (commentBufferSize is the size of the buffer)
-*/
-
-/***************************************************************************/
-/* for reading the content of the current zipfile, you can open it, read data
- from it, and close it (you can close it before reading all the file)
- */
-
-extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
-/*
- Open for reading data the current file in the zipfile.
- If there is no error, the return value is UNZ_OK.
-*/
-
-extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
-/*
- Close the file in zip opened with unzOpenCurrentFile
- Return UNZ_CRCERROR if all the file was read but the CRC is not good
-*/
-
-
-extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
- voidp buf,
- unsigned len));
-/*
- Read bytes from the current file (opened by unzOpenCurrentFile)
- buf contain buffer where data must be copied
- len the size of buf.
-
- return the number of byte copied if somes bytes are copied
- return 0 if the end of file was reached
- return <0 with error code if there is an error
- (UNZ_ERRNO for IO error, or zLib error for uncompress error)
-*/
+#include "common/scummsys.h"
+#include "common/archive.h"
-extern z_off_t ZEXPORT unztell OF((unzFile file));
-/*
- Give the current position in uncompressed data
-*/
+typedef void *unzFile;
-extern int ZEXPORT unzeof OF((unzFile file));
-/*
- return 1 if the end of file was reached, 0 elsewhere
-*/
+namespace Common {
-extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
- voidp buf,
- unsigned len));
-/*
- Read extra field from the current file (opened by unzOpenCurrentFile)
- This is the local-header version of the extra field (sometimes, there is
- more info in the local-header version than in the central-header)
+class ZipArchive : public Archive {
+ void *_zipFile;
- if buf==NULL, it return the size of the local extra field
+public:
+ ZipArchive(const String &name);
+ ~ZipArchive();
+
+ bool isOpen() const;
- if buf!=NULL, len is the size of the buffer, the extra header is copied in
- buf.
- the return value is the number of bytes copied in buf, or (if <0)
- the error code
-*/
+ virtual bool hasFile(const String &name);
+ virtual int getAllNames(StringList &list); // FIXME: This one is not (yet?) implemented
+ virtual Common::SeekableReadStream *openFile(const Common::String &name);
+};
-#ifdef __cplusplus
-}
-#endif
+} // End of namespace Common
-#endif
+#endif // USE_ZLIB
#endif /* _unz_H */
diff --git a/common/util.cpp b/common/util.cpp
index 6f0fdcb233..f68d253ec3 100644
--- a/common/util.cpp
+++ b/common/util.cpp
@@ -63,39 +63,6 @@ extern bool isSmartphone(void);
namespace Common {
-bool matchString(const char *str, const char *pat) {
- const char *p = 0;
- const char *q = 0;
-
- for (;;) {
- switch (*pat) {
- case '*':
- p = ++pat;
- q = str;
- break;
-
- default:
- if (*pat != *str) {
- if (p) {
- pat = p;
- str = ++q;
- if (!*str)
- return !*pat;
- break;
- }
- else
- return false;
- }
- // fallthrough
- case '?':
- if (!*str)
- return !*pat;
- pat++;
- str++;
- }
- }
-}
-
StringTokenizer::StringTokenizer(const String &str, const String &delimiters) : _str(str), _delimiters(delimiters) {
reset();
}
@@ -237,10 +204,9 @@ Language parseLanguage(const String &str) {
if (str.empty())
return UNK_LANG;
- const char *s = str.c_str();
const LanguageDescription *l = g_languages;
for (; l->code; ++l) {
- if (!scumm_stricmp(l->code, s))
+ if (str.equalsIgnoreCase(l->code))
return l->id;
}
@@ -278,6 +244,7 @@ const PlatformDescription g_platforms[] = {
{"c64", "c64", "c64", "Commodore 64", kPlatformC64},
{"pc", "dos", "ibm", "DOS", kPlatformPC},
{"pc98", "pc98", "pc98", "PC-98", kPlatformPC98},
+ {"wii", "wii", "wii", "Nintendo Wii", kPlatformWii},
// The 'official' spelling seems to be "FM-TOWNS" (e.g. in the Indy4 demo).
// However, on the net many variations can be seen, like "FMTOWNS",
@@ -299,20 +266,18 @@ Platform parsePlatform(const String &str) {
if (str.empty())
return kPlatformUnknown;
- const char *s = str.c_str();
-
// Handle some special case separately, for compatibility with old config
// files.
- if (!strcmp(s, "1"))
+ if (str == "1")
return kPlatformAmiga;
- else if (!strcmp(s, "2"))
+ else if (str == "2")
return kPlatformAtariST;
- else if (!strcmp(s, "3"))
+ else if (str == "3")
return kPlatformMacintosh;
const PlatformDescription *l = g_platforms;
for (; l->code; ++l) {
- if (!scumm_stricmp(l->code, s) || !scumm_stricmp(l->code2, s) || !scumm_stricmp(l->abbrev, s))
+ if (str.equalsIgnoreCase(l->code) || str.equalsIgnoreCase(l->code2) || str.equalsIgnoreCase(l->abbrev))
return l->id;
}
@@ -364,10 +329,9 @@ RenderMode parseRenderMode(const String &str) {
if (str.empty())
return kRenderDefault;
- const char *s = str.c_str();
const RenderModeDescription *l = g_renderModes;
for (; l->code; ++l) {
- if (!scumm_stricmp(l->code, s))
+ if (str.equalsIgnoreCase(l->code))
return l->id;
}
diff --git a/common/util.h b/common/util.h
index c23513596c..573004c437 100644
--- a/common/util.h
+++ b/common/util.h
@@ -53,28 +53,6 @@ template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; }
namespace Common {
/**
- * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
- * Taken from exult/files/listfiles.cc
- *
- * Token meaning:
- * "*": any character, any amount of times.
- * "?": any character, only once.
- *
- * Example strings/patterns:
- * String: monkey.s?? Pattern: monkey.s01 => true
- * String: monkey.s?? Pattern: monkey.s101 => false
- * String: monkey.s?1 Pattern: monkey.s99 => false
- * String: monkey.s* Pattern: monkey.s101 => true
- * String: monkey.s*1 Pattern: monkey.s99 => false
- *
- * @param str Text to be matched against the given pattern.
- * @param pat Glob pattern.
- *
- * @return true if str matches the pattern, false otherwise.
- */
-bool matchString(const char *str, const char *pat);
-
-/**
* A simple non-optimized string tokenizer.
*
* Example of use:
@@ -128,20 +106,20 @@ public:
/**
* Generates a random unsigned integer in the interval [0, max].
* @param max the upper bound
- * @return a random number in the interval [0, max].
+ * @return a random number in the interval [0, max]
*/
uint getRandomNumber(uint max);
/**
- * Generates a random unsigned integer in the interval [0, 1].
+ * Generates a random bit, i.e. either 0 or 1.
* Identical to getRandomNumber(1), but faster, hopefully.
- * @return a random number in the interval [0, max].
+ * @return a random bit, either 0 or 1
*/
uint getRandomBit(void);
/**
* Generates a random unsigned integer in the interval [min, max].
* @param min the lower bound
* @param max the upper bound
- * @return a random number in the interval [min, max].
+ * @return a random number in the interval [min, max]
*/
uint getRandomNumberRng(uint min, uint max);
};
@@ -210,6 +188,7 @@ enum Platform {
kPlatformApple2GS,
kPlatformPC98,
+ kPlatformWii,
kPlatformUnknown = -1
};
diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp
index 900f2f81ab..b93a5205be 100644
--- a/common/xmlparser.cpp
+++ b/common/xmlparser.cpp
@@ -37,7 +37,8 @@ using namespace Graphics;
bool XMLParser::parserError(const char *errorString, ...) {
_state = kParserError;
- int pos = _pos;
+ int original_pos = _stream->pos();
+ int pos = original_pos;
int lineCount = 1;
int lineStart = 0;
@@ -46,18 +47,21 @@ bool XMLParser::parserError(const char *errorString, ...) {
lineCount = 0;
} else {
do {
- if (_text[pos] == '\n' || _text[pos] == '\r') {
+ if (_char == '\n' || _char == '\r') {
lineCount++;
if (lineStart == 0)
lineStart = MAX(pos + 1, _pos - 60);
}
- } while (pos-- > 0);
+
+ _stream->seek(-1, SEEK_CUR);
+
+ } while (_stream->pos() > 0);
}
char lineStr[70];
- _text.stream()->seek(lineStart, SEEK_SET);
- _text.stream()->readLine(lineStr, 70);
+ _stream->seek(original_pos - 35, SEEK_SET);
+ _stream->readLine_NEW(lineStr, 70);
for (int i = 0; i < 70; ++i)
if (lineStr[i] == '\n')
@@ -70,7 +74,7 @@ bool XMLParser::parserError(const char *errorString, ...) {
printf("%s%s%s\n", startFull ? "" : "...", lineStr, endFull ? "" : "...");
- int cursor = MIN(_pos - lineStart, 70);
+ int cursor = 35;
if (!startFull)
cursor += 3;
@@ -102,15 +106,16 @@ bool XMLParser::parseActiveKey(bool closed) {
key->layout = layout->children[key->name];
Common::StringMap localMap = key->values;
+ int keyCount = localMap.size();
for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator i = key->layout->properties.begin(); i != key->layout->properties.end(); ++i) {
- if (localMap.contains(i->name))
- localMap.erase(i->name);
- else if (i->required)
+ if (i->required && !localMap.contains(i->name))
return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str());
+ else if (localMap.contains(i->name))
+ keyCount--;
}
- if (localMap.empty() == false)
+ if (keyCount > 0)
return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str());
} else {
@@ -149,15 +154,20 @@ bool XMLParser::parseKeyValue(Common::String keyName) {
_token.clear();
char stringStart;
- if (_text[_pos] == '"' || _text[_pos] == '\'') {
- stringStart = _text[_pos++];
+ if (_char == '"' || _char == '\'') {
+ stringStart = _char;
+ _char = _stream->readByte();
- while (_text[_pos] && _text[_pos] != stringStart)
- _token += _text[_pos++];
+ while (_char && _char != stringStart) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
- if (_text[_pos++] == 0)
+ if (_char == 0)
return false;
+ _char = _stream->readByte();
+
} else if (!parseToken()) {
return false;
}
@@ -185,7 +195,7 @@ bool XMLParser::closeKey() {
bool XMLParser::parse() {
- if (_text.ready() == false)
+ if (_stream == 0)
return parserError("XML stream not ready for reading.");
if (_XMLkeys == 0)
@@ -202,8 +212,10 @@ bool XMLParser::parse() {
_state = kParserNeedKey;
_pos = 0;
_activeKey.clear();
+
+ _char = _stream->readByte();
- while (_text[_pos] && _state != kParserError) {
+ while (_char && _state != kParserError) {
if (skipSpaces())
continue;
@@ -212,18 +224,18 @@ bool XMLParser::parse() {
switch (_state) {
case kParserNeedKey:
- if (_text[_pos++] != '<') {
+ if (_char != '<') {
parserError("Parser expecting key start.");
break;
}
- if (_text[_pos] == 0) {
+ if ((_char = _stream->readByte()) == 0) {
parserError("Unexpected end of file.");
break;
}
- if (_text[_pos] == '/' && _text[_pos + 1] != '*') {
- _pos++;
+ if (_char == '/') { // FIXME: What if it's a comment start
+ _char = _stream->readByte();
activeClosure = true;
}
@@ -262,19 +274,25 @@ bool XMLParser::parse() {
activeClosure = false;
- if (_text[_pos++] != '>')
+ if (_char != '>')
parserError("Invalid syntax in key closure.");
else
_state = kParserNeedKey;
+ _char = _stream->readByte();
break;
}
- selfClosure = (_text[_pos] == '/');
+ selfClosure = false;
+
+ if (_char == '/') { // FIXME: comment start?
+ selfClosure = true;
+ _char = _stream->readByte();
+ }
- if ((selfClosure && _text[_pos + 1] == '>') || _text[_pos] == '>') {
+ if (_char == '>') {
if (parseActiveKey(selfClosure)) {
- _pos += selfClosure ? 2 : 1;
+ _char = _stream->readByte();
_state = kParserNeedKey;
}
break;
@@ -288,11 +306,12 @@ bool XMLParser::parse() {
break;
case kParserNeedPropertyOperator:
- if (_text[_pos++] != '=')
+ if (_char != '=')
parserError("Syntax error after key name.");
else
_state = kParserNeedPropertyValue;
+ _char = _stream->readByte();
break;
case kParserNeedPropertyValue:
diff --git a/common/xmlparser.h b/common/xmlparser.h
index 4d1c8fc85d..dcbfc60c2f 100644
--- a/common/xmlparser.h
+++ b/common/xmlparser.h
@@ -40,145 +40,12 @@
namespace Common {
-/***********************************************
- **** XMLParser.cpp/h -- Generic XML Parser ****
- ***********************************************
+/*
+ XMLParser.cpp/h -- Generic XML Parser
+ =====================================
- This is a simple implementation of a generic parser which is able to
- interpret a subset of the XML language.
-
- The XMLParser class is virtual, and must be derived into a child class,
- called a Custom Parser Class, which will manage the parsed data for your
- specific needs.
-
- Custom Parser Classes have two basic requirements:
- They must inherit directly the XMLParser class, and they must define the
- parsing layout of the XML file.
-
- Declaring the XML layout is done with the help of the CUSTOM_XML_PARSER()
- macro: this macro must appear once inside the Custom Parser Class
- declaration, and takes a single parameter, the name of the Custom Parser
- Class.
-
- The macro must be followed by the actual layout of the XML files to be
- parsed, and closed with the PARSER_END() macro. The layout of XML files
- is defined by the use of 3 helper macros: XML_KEY(), KEY_END() and
- XML_PROP().
-
- Here's a sample of its usage:
-
- =========== =========== =========== =========== =========== ===========
-
- CUSTOM_XML_PARSER(ThemeParser) {
- XML_KEY(render_info)
- XML_KEY(palette)
- XML_KEY(color)
- XML_PROP(name, true)
- XML_PROP(rgb, true)
- KEY_END()
- KEY_END()
-
- XML_KEY(fonts)
- XML_KEY(font)
- XML_PROP(id, true)
- XML_PROP(type, true)
- XML_PROP(color, true)
- KEY_END()
- KEY_END()
-
- XML_KEY(defaults)
- XML_PROP(stroke, false)
- XML_PROP(shadow, false)
- XML_PROP(factor, false)
- XML_PROP(fg_color, false)
- XML_PROP(bg_color, false)
- XML_PROP(gradient_start, false)
- XML_PROP(gradient_end, false)
- XML_PROP(gradient_factor, false)
- XML_PROP(fill, false)
- KEY_END()
- KEY_END()
- } PARSER_END()
-
- =========== =========== =========== =========== =========== ===========
-
- The XML_KEY() macro takes a single argument, the name of the expected key.
- Inside the scope of each key, you may define properties for the given key
- with the XML_PROP() macro, which takes as parameters the name of the
- property and whether it's optional or required. You might also define the
- contained children keys, using the XML_KEY() macro again.
- The scope of a XML key is closed with the KEY_END() macro.
-
- Keys which may contain any kind of Property names may be defined with the
- XML_PROP_ANY() macro instead of the XML_PROP() macro. This macro takes no
- arguments.
-
- As an example, the following XML layout:
-
- XML_KEY(palette)
- XML_KEY(color)
- XML_PROP(name, true)
- XML_PROP(rgb, true)
- XML_PROP(optional_param, false)
- KEY_END()
- KEY_END()
-
- will expect to parse a syntax like this:
-
- <palette>
- <color name = "red" rgb = "255, 0, 0" />
- <color name = "blue" rgb = "0, 0, 255" optional_param = "565" />
- </palette>
-
- Once a layout has been defined, everytime a XML node (that is, a key and
- all its properties) has been parsed, a specific callback funcion is called,
- which should take care of managing the parsed data for the node.
-
- Callback functions must be explicitly declared with the following syntax:
-
- bool parserCallback_KEYNAME(ParserNode *node);
-
- A callback function is needed for each key that can be parsed, since they
- are called automatically; the function will receive a pointer to the XML
- Node that has been parsed. This XML Node has the following properties:
-
- - It's assured to be expected in the layout of the XML file (i.e.
- has the proper position and depth in the XML tree).
-
- - It's assured to contain all the required Properties that have
- been declared in the XML layout.
-
- - It's assured to contain NO unexpected properties (i.e. properties
- which haven't been declared in the XML layout).
-
- Further validation of the Node's data may be performed inside the callback
- function. Once the node has been validated and its data has been parsed/
- managed, the callback function is expected to return true.
-
- If the data in the XML Node is corrupted or there was a problem when
- parsing it, the callback function is expected to return false or,
- preferably, to throw a parserError() using the following syntax:
-
- return parserError("There was a problem in key '%s'.", arg1, ...);
-
- Also, note that the XML parser doesn't take into account the actual order
- of the keys and properties in the XML layout definition, only its layout
- and relationships.
-
- Lastly, when defining your own Custom XML Parser, further customization
- may be accomplished _optionally_ by overloading several virtual functions
- of the XMLParser class.
-
- Check the API documentation of the following functions for more info:
-
- virtual bool closedKeyCallback(ParserNode *node);
- virtual bool skipComments();
- virtual bool isValidNameChar(char c);
- virtual void cleanup();
-
- Check the sample implementation of the GUI::ThemeParser custom parser
- for a working sample of a Custom XML Parser.
-
+ External documentation available at:
+ http://www.smartlikearoboc.com/scummvm_doc/xmlparser_doc.html
*/
#define XML_KEY(keyName) {\
@@ -226,43 +93,6 @@ namespace Common {
#define PARSER_END() layout.clear(); }
-class XMLStream {
-protected:
- SeekableReadStream *_stream;
- int _pos;
-
-public:
- XMLStream() : _stream(0), _pos(0) {}
-
- ~XMLStream() {
- delete _stream;
- }
-
- SeekableReadStream *stream() {
- return _stream;
- }
-
- char operator [](int idx) {
- assert(_stream && idx >= 0);
-
- if (_pos + 1 != idx)
- _stream->seek(idx, SEEK_SET);
-
- _pos = idx;
-
- return _stream->readByte();
- }
-
- void loadStream(SeekableReadStream *s) {
- delete _stream;
- _stream = s;
- }
-
- bool ready() {
- return _stream != 0;
- }
-};
-
/**
* The base XMLParser class implements generic functionality for parsing
* XML-like files.
@@ -278,13 +108,14 @@ public:
/**
* Parser constructor.
*/
- XMLParser() : _XMLkeys(0) {}
+ XMLParser() : _XMLkeys(0), _stream(0) {}
virtual ~XMLParser() {
while (!_activeKey.empty())
delete _activeKey.pop();
delete _XMLkeys;
+ delete _stream;
for (Common::List<XMLKeyLayout*>::iterator i = _layoutList.begin();
i != _layoutList.end(); ++i)
@@ -352,7 +183,7 @@ public:
}
_fileName = filename;
- _text.loadStream(f);
+ _stream = f;
return true;
}
@@ -365,7 +196,7 @@ public:
}
_fileName = node.getName();
- _text.loadStream(f);
+ _stream = f;
return true;
}
@@ -381,13 +212,13 @@ public:
* no longer needed by the parser.
*/
bool loadBuffer(const byte *buffer, uint32 size, bool disposable = false) {
- _text.loadStream(new MemoryReadStream(buffer, size, disposable));
+ _stream = new MemoryReadStream(buffer, size, disposable);
_fileName = "Memory Stream";
return true;
}
- bool loadStream(MemoryReadStream *stream) {
- _text.loadStream(stream);
+ bool loadStream(SeekableReadStream *stream) {
+ _stream = stream;
_fileName = "Compressed File Stream";
return true;
}
@@ -492,11 +323,11 @@ protected:
* Skips spaces/whitelines etc. Returns true if any spaces were skipped.
*/
bool skipSpaces() {
- if (!isspace(_text[_pos]))
+ if (!isspace(_char))
return false;
- while (_text[_pos] && isspace(_text[_pos]))
- _pos++;
+ while (_char && isspace(_char))
+ _char = _stream->readByte();
return true;
}
@@ -508,14 +339,31 @@ protected:
* or to change the commenting syntax.
*/
virtual bool skipComments() {
- if (_text[_pos] == '/' && _text[_pos + 1] == '*') {
- _pos += 2;
- while (_text[_pos++]) {
- if (_text[_pos - 2] == '*' && _text[_pos - 1] == '/')
+ char endComment1 = 0, endComment2 = 0;
+
+ if (_char == '/') {
+ _char = _stream->readByte();
+
+ if (_char != '*') {
+ _stream->seek(-1, SEEK_CUR);
+ _char = '/';
+ return false;
+ }
+
+ _char = _stream->readByte();
+
+ while (_char) {
+ endComment1 = endComment2;
+ endComment2 = _char;
+ _char = _stream->readByte();
+
+ if (endComment1 == '*' && endComment2 == '/')
break;
- if (_text[_pos] == 0)
+
+ if (_char == 0)
parserError("Comment has no closure.");
}
+ _char = _stream->readByte();
return true;
}
@@ -527,7 +375,7 @@ protected:
* Overload this if you want to support keys with strange characters
* in their name.
*/
- virtual bool isValidNameChar(char c) {
+ virtual inline bool isValidNameChar(char c) {
return isalnum(c) || c == '_';
}
@@ -537,10 +385,13 @@ protected:
*/
bool parseToken() {
_token.clear();
- while (isValidNameChar(_text[_pos]))
- _token += _text[_pos++];
- return isspace(_text[_pos]) != 0 || _text[_pos] == '>' || _text[_pos] == '=' || _text[_pos] == '/';
+ while (isValidNameChar(_char)) {
+ _token += _char;
+ _char = _stream->readByte();
+ }
+
+ return isspace(_char) != 0 || _char == '>' || _char == '=' || _char == '/';
}
/**
@@ -599,7 +450,8 @@ protected:
private:
int _pos; /** Current position on the XML buffer. */
- XMLStream _text; /** Buffer with the text being parsed */
+ char _char;
+ SeekableReadStream *_stream;
Common::String _fileName;
ParserState _state; /** Internal state of the parser */
diff --git a/common/zlib.cpp b/common/zlib.cpp
index 7e14a9e3ab..4ed233b4b0 100644
--- a/common/zlib.cpp
+++ b/common/zlib.cpp
@@ -8,37 +8,327 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
+ *
*/
#include "common/zlib.h"
+#include "common/util.h"
#if defined(USE_ZLIB)
+ #ifdef __SYMBIAN32__
+ #include <zlib\zlib.h>
+ #else
+ #include <zlib.h>
+ #endif
-#ifdef __SYMBIAN32__
-#include <zlib\zlib.h>
-#else
-#include <zlib.h>
+ #if ZLIB_VERNUM < 0x1204
+ #error Version 1.2.0.4 or newer of zlib is required for this code
+ #endif
#endif
+
namespace Common {
-int uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) {
- return ::uncompress(dst, dstLen, src, srcLen);
+#if defined(USE_ZLIB)
+
+bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) {
+ return Z_OK == ::uncompress(dst, dstLen, src, srcLen);
}
-} // end of namespace Common
+/**
+ * A simple wrapper class which can be used to wrap around an arbitrary
+ * other SeekableReadStream and will then provide on-the-fly decompression support.
+ * Assumes the compressed data to be in gzip format.
+ */
+class GZipReadStream : public Common::SeekableReadStream {
+protected:
+ enum {
+ BUFSIZE = 16384 // 1 << MAX_WBITS
+ };
+
+ byte _buf[BUFSIZE];
+
+ Common::SeekableReadStream *_wrapped;
+ z_stream _stream;
+ int _zlibErr;
+ uint32 _pos;
+ uint32 _origSize;
+ bool _eos;
+
+public:
+
+ GZipReadStream(Common::SeekableReadStream *w) : _wrapped(w) {
+ assert(w != 0);
+
+ _stream.zalloc = Z_NULL;
+ _stream.zfree = Z_NULL;
+ _stream.opaque = Z_NULL;
+
+ // Verify file header is correct
+ w->seek(0, SEEK_SET);
+ uint16 header = w->readUint16BE();
+ assert(header == 0x1F8B ||
+ ((header & 0x0F00) == 0x0800 && header % 31 == 0));
+
+ if (header == 0x1F8B) {
+ // Retrieve the original file size
+ w->seek(-4, SEEK_END);
+ _origSize = w->readUint32LE();
+ } else {
+ // Original size not available in zlib format
+ _origSize = 0;
+ }
+ _pos = 0;
+ w->seek(0, SEEK_SET);
+ _eos = false;
+
+ // Adding 32 to windowBits indicates to zlib that it is supposed to
+ // automatically detect whether gzip or zlib headers are used for
+ // the compressed file. This feature was added in zlib 1.2.0.4,
+ // released 10 August 2003.
+ // Note: This is *crucial* for savegame compatibility, do *not* remove!
+ _zlibErr = inflateInit2(&_stream, MAX_WBITS + 32);
+ if (_zlibErr != Z_OK)
+ return;
+
+ // Setup input buffer
+ _stream.next_in = _buf;
+ _stream.avail_in = 0;
+ }
+
+ ~GZipReadStream() {
+ inflateEnd(&_stream);
+ delete _wrapped;
+ }
+
+ bool err() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); }
+ void clearErr() {
+ // only reset _eos; I/O errors are not recoverable
+ _eos = false;
+ }
+
+ uint32 read(void *dataPtr, uint32 dataSize) {
+ _stream.next_out = (byte *)dataPtr;
+ _stream.avail_out = dataSize;
+
+ // Keep going while we get no error
+ while (_zlibErr == Z_OK && _stream.avail_out) {
+ if (_stream.avail_in == 0 && !_wrapped->eos()) {
+ // If we are out of input data: Read more data, if available.
+ _stream.next_in = _buf;
+ _stream.avail_in = _wrapped->read(_buf, BUFSIZE);
+ }
+ _zlibErr = inflate(&_stream, Z_NO_FLUSH);
+ }
+
+ // Update the position counter
+ _pos += dataSize - _stream.avail_out;
+
+ if (_zlibErr == Z_STREAM_END && _stream.avail_out > 0)
+ _eos = true;
+
+ return dataSize - _stream.avail_out;
+ }
+
+ bool eos() const {
+ return _eos;
+ }
+ int32 pos() const {
+ return _pos;
+ }
+ int32 size() const {
+ return _origSize;
+ }
+ bool seek(int32 offset, int whence = SEEK_SET) {
+ int32 newPos = 0;
+ assert(whence != SEEK_END); // SEEK_END not supported
+ switch(whence) {
+ case SEEK_SET:
+ newPos = offset;
+ break;
+ case SEEK_CUR:
+ newPos = _pos + offset;
+ }
+
+ assert(newPos >= 0);
+
+ if ((uint32)newPos < _pos) {
+ // To search backward, we have to restart the whole decompression
+ // from the start of the file. A rather wasteful operation, best
+ // to avoid it. :/
+#if DEBUG
+ warning("Backward seeking in GZipReadStream detected");
+#endif
+ _pos = 0;
+ _wrapped->seek(0, SEEK_SET);
+ _zlibErr = inflateReset(&_stream);
+ if (_zlibErr != Z_OK)
+ return false; // FIXME: STREAM REWRITE
+ _stream.next_in = _buf;
+ _stream.avail_in = 0;
+ }
+
+ offset = newPos - _pos;
+
+ // Skip the given amount of data (very inefficient if one tries to skip
+ // huge amounts of data, but usually client code will only skip a few
+ // bytes, so this should be fine.
+ byte tmpBuf[1024];
+ while (!err() && offset > 0) {
+ offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset));
+ }
+
+ _eos = false;
+ return true; // FIXME: STREAM REWRITE
+ }
+};
+
+/**
+ * A simple wrapper class which can be used to wrap around an arbitrary
+ * other WriteStream and will then provide on-the-fly compression support.
+ * The compressed data is written in the gzip format.
+ */
+class GZipWriteStream : public Common::WriteStream {
+protected:
+ enum {
+ BUFSIZE = 16384 // 1 << MAX_WBITS
+ };
+
+ byte _buf[BUFSIZE];
+ Common::WriteStream *_wrapped;
+ z_stream _stream;
+ int _zlibErr;
+
+ void processData(int flushType) {
+ // This function is called by both write() and finalize().
+ while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) {
+ if (_stream.avail_out == 0) {
+ if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) {
+ _zlibErr = Z_ERRNO;
+ break;
+ }
+ _stream.next_out = _buf;
+ _stream.avail_out = BUFSIZE;
+ }
+ _zlibErr = deflate(&_stream, flushType);
+ }
+ }
+
+public:
+ GZipWriteStream(Common::WriteStream *w) : _wrapped(w) {
+ assert(w != 0);
+ _stream.zalloc = Z_NULL;
+ _stream.zfree = Z_NULL;
+ _stream.opaque = Z_NULL;
+
+ // Adding 16 to windowBits indicates to zlib that it is supposed to
+ // write gzip headers. This feature was added in zlib 1.2.0.4,
+ // released 10 August 2003.
+ // Note: This is *crucial* for savegame compatibility, do *not* remove!
+ _zlibErr = deflateInit2(&_stream,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ MAX_WBITS + 16,
+ 8,
+ Z_DEFAULT_STRATEGY);
+ assert(_zlibErr == Z_OK);
+
+ _stream.next_out = _buf;
+ _stream.avail_out = BUFSIZE;
+ _stream.avail_in = 0;
+ _stream.next_in = 0;
+ }
+
+ ~GZipWriteStream() {
+ finalize();
+ deflateEnd(&_stream);
+ delete _wrapped;
+ }
+
+ bool err() const {
+ // CHECKME: does Z_STREAM_END make sense here?
+ return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->err();
+ }
+
+ void clearErr() {
+ // Note: we don't reset the _zlibErr here, as it is not
+ // clear in general how
+ _wrapped->clearErr();
+ }
+
+ void finalize() {
+ if (_zlibErr != Z_OK)
+ return;
+
+ // Process whatever remaining data there is.
+ processData(Z_FINISH);
+ // Since processData only writes out blocks of size BUFSIZE,
+ // we may have to flush some stragglers.
+ uint remainder = BUFSIZE - _stream.avail_out;
+ if (remainder > 0) {
+ if (_wrapped->write(_buf, remainder) != remainder) {
+ _zlibErr = Z_ERRNO;
+ }
+ }
+
+ // Finalize the wrapped savefile, too
+ _wrapped->finalize();
+ }
+
+ uint32 write(const void *dataPtr, uint32 dataSize) {
+ if (err())
+ return 0;
+
+ // Hook in the new data ...
+ // Note: We need to make a const_cast here, as zlib is not aware
+ // of the const keyword.
+ _stream.next_in = const_cast<byte *>((const byte *)dataPtr);
+ _stream.avail_in = dataSize;
+
+ // ... and flush it to disk
+ processData(Z_NO_FLUSH);
+
+ return dataSize - _stream.avail_in;
+ }
+};
+
+#endif // USE_ZLIB
+
+Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped) {
+#if defined(USE_ZLIB)
+ if (toBeWrapped) {
+ uint16 header = toBeWrapped->readUint16BE();
+ bool isCompressed = (header == 0x1F8B ||
+ ((header & 0x0F00) == 0x0800 &&
+ header % 31 == 0));
+ toBeWrapped->seek(-2, SEEK_CUR);
+ if (isCompressed)
+ return new GZipReadStream(toBeWrapped);
+ }
#endif
+ return toBeWrapped;
+}
+
+Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped) {
+#if defined(USE_ZLIB)
+ if (toBeWrapped)
+ return new GZipWriteStream(toBeWrapped);
+#endif
+ return toBeWrapped;
+}
+
+} // End of namespace Common
diff --git a/common/zlib.h b/common/zlib.h
index 62e9f98c01..5fd13e842d 100644
--- a/common/zlib.h
+++ b/common/zlib.h
@@ -8,44 +8,65 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
+ *
*/
-#include "common/scummsys.h"
-
-#if defined(USE_ZLIB)
-
#ifndef COMMON_ZLIB_H
#define COMMON_ZLIB_H
-#ifdef __SYMBIAN32__
-#include <zlib\zlib.h>
-#else
-#include <zlib.h>
-#endif
+#include "common/scummsys.h"
+#include "common/stream.h"
namespace Common {
-enum {
- ZLIB_OK = Z_OK
-};
-
-int uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen);
+#if defined(USE_ZLIB)
-} // end of namespace Common
+/**
+ * Thin wrapper around zlib's uncompress() function. This wrapper makes
+ * it possible to uncompress data in engines without being forced to link
+ * them against zlib, thus simplifying the build system.
+ *
+ * @return true on success (i.e. Z_OK), false otherwise
+ */
+bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen);
#endif
-#endif
+/**
+ * Take an arbitrary SeekableReadStream and wrap it in a custom stream which
+ * provides transparent on-the-fly decompression. Assumes the data it
+ * retrieves from the wrapped stream to be either uncompressed or in gzip
+ * format. In the former case, the original stream is returned unmodified
+ * (and in particular, not wrapped).
+ *
+ * It is safe to call this with a NULL parameter (in this case, NULL is
+ * returned).
+ */
+Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped);
+/**
+ * Take an arbitrary WriteStream and wrap it in a custom stream which provides
+ * transparent on-the-fly compression. The compressed data is written in the
+ * gzip format, unless ZLIB support has been disabled, in which case the given
+ * stream is returned unmodified (and in particular, not wrapped).
+ *
+ * It is safe to call this with a NULL parameter (in this case, NULL is
+ * returned).
+ */
+Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped);
+
+} // End of namespace Common
+
+#endif
diff --git a/configure b/configure
index 037c0bf786..c54a955deb 100755
--- a/configure
+++ b/configure
@@ -904,7 +904,7 @@ if test "$?" -gt 0; then
fi
case $cxx_version in
- 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*)
+ 2.95.[2-9]|2.95.[2-9][-.]*|3.[0-9]|3.[0-9].[0-9]|3.[0-9].[0-9][-.]*|4.[0-9]|4.[0-9].[0-9]|4.[0-9].[0-9][-.]*)
_cxx_major=`echo $cxx_version | cut -d '.' -f 1`
_cxx_minor=`echo $cxx_version | cut -d '.' -f 2`
cxx_version="$cxx_version, ok"
@@ -1030,7 +1030,6 @@ echo "$_have_x86"
#
# Determine build settings
#
-# TODO - also add an command line option to override this?!?
echo_n "Checking hosttype... "
echo $_host_os
case $_host_os in
@@ -1046,7 +1045,7 @@ case $_host_os in
type_4_byte='long'
;;
solaris*)
- DEFINES="$DEFINES -DUNIX -DSYSTEM_NOT_SUPPORTING_D_TYPE"
+ DEFINES="$DEFINES -DUNIX -DSOLARIS -DSYSTEM_NOT_SUPPORTING_D_TYPE"
# Needs -lbind -lsocket for the timidity MIDI driver
LIBS="$LIBS -lnsl -lsocket"
;;
@@ -1060,12 +1059,12 @@ case $_host_os in
LIBS="$LIBS -framework QuickTime -framework AudioUnit -framework AudioToolbox -framework Carbon -framework CoreMIDI"
;;
mingw*)
- DEFINES="$DEFINES -DWIN32"
+ DEFINES="$DEFINES -DWIN32 -D__USE_MINGW_ANSI_STDIO=0"
LIBS="$LIBS -lmingw32 -lwinmm"
OBJS="$OBJS scummvmico.o"
;;
cygwin*)
- DEFINES="$DEFINES -mno-cygwin -DWIN32"
+ DEFINES="$DEFINES -mno-cygwin -DWIN32 -D__USE_MINGW_ANSI_STDIO=0"
LIBS="$LIBS -mno-cygwin -lmingw32 -lwinmm"
OBJS="$OBJS scummvmico.o"
;;
@@ -1074,7 +1073,6 @@ case $_host_os in
;;
mint*)
DEFINES="$DEFINES -DUNIX -DSYSTEM_NOT_SUPPORTING_D_TYPE"
- LIBS="$LIBS -lsocket"
;;
amigaos*)
# TODO: anything to be added here?
diff --git a/dists/engine-data/drascula.dat b/dists/engine-data/drascula.dat
index 321e63c277..1602a42490 100644
--- a/dists/engine-data/drascula.dat
+++ b/dists/engine-data/drascula.dat
Binary files differ
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 7171707e8b..572106f4a4 100644
--- a/dists/engine-data/kyra.dat
+++ b/dists/engine-data/kyra.dat
Binary files differ
diff --git a/dists/macosx/Info.plist.in b/dists/macosx/Info.plist.in
index 9074acc876..b87e9501e5 100644
--- a/dists/macosx/Info.plist.in
+++ b/dists/macosx/Info.plist.in
@@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>scummvm</string>
<key>CFBundleGetInfoString</key>
- <string>@VERSION@, Copyright 2001-2007 The ScummVM team</string>
+ <string>@VERSION@, Copyright 2001-2008 The ScummVM team</string>
<key>CFBundleIconFile</key>
<string>scummvm.icns</string>
<key>CFBundleIdentifier</key>
@@ -27,6 +27,6 @@
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHumanReadableCopyright</key>
- <string>Copyright 2001-2007 The ScummVM team</string>
+ <string>Copyright 2001-2008 The ScummVM team</string>
</dict>
</plist>
diff --git a/dists/msvc7/agi.vcproj b/dists/msvc7/agi.vcproj
index d8154d907a..7da2e9397d 100644
--- a/dists/msvc7/agi.vcproj
+++ b/dists/msvc7/agi.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="agi_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/agos.vcproj b/dists/msvc7/agos.vcproj
index 4a64e17d34..5aad20fa99 100644
--- a/dists/msvc7/agos.vcproj
+++ b/dists/msvc7/agos.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="agos_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/cine.vcproj b/dists/msvc7/cine.vcproj
index fe0abd0f27..16d0e6161f 100644
--- a/dists/msvc7/cine.vcproj
+++ b/dists/msvc7/cine.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="cine_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/cruise.vcproj b/dists/msvc7/cruise.vcproj
index bac134e02c..24a423e737 100644
--- a/dists/msvc7/cruise.vcproj
+++ b/dists/msvc7/cruise.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="cruise_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -145,9 +152,6 @@
RelativePath="..\..\engines\cruise\dataLoader.h">
</File>
<File
- RelativePath="..\..\engines\cruise\decompiler.cpp">
- </File>
- <File
RelativePath="..\..\engines\cruise\delphine-unpack.cpp">
</File>
<File
diff --git a/dists/msvc7/drascula.vcproj b/dists/msvc7/drascula.vcproj
index 2d23296dbc..7d4d55b00c 100644
--- a/dists/msvc7/drascula.vcproj
+++ b/dists/msvc7/drascula.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="drascula_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/gob.vcproj b/dists/msvc7/gob.vcproj
index bb7eac35e0..99edd6deb2 100644
--- a/dists/msvc7/gob.vcproj
+++ b/dists/msvc7/gob.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="gob_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -268,6 +275,12 @@
RelativePath="..\..\engines\gob\inter_v4.cpp">
</File>
<File
+ RelativePath="..\..\engines\gob\inter_v5.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\gob\inter_v6.cpp">
+ </File>
+ <File
RelativePath="..\..\engines\gob\map.cpp">
</File>
<File
@@ -364,6 +377,9 @@
RelativePath="..\..\engines\gob\video_v2.cpp">
</File>
<File
+ RelativePath="..\..\engines\gob\video_v6.cpp">
+ </File>
+ <File
RelativePath="..\..\engines\gob\videoplayer.cpp">
</File>
<File
diff --git a/dists/msvc7/igor.vcproj b/dists/msvc7/igor.vcproj
index cbc5c9b7ec..46af401294 100644
--- a/dists/msvc7/igor.vcproj
+++ b/dists/msvc7/igor.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="igor_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/kyra.vcproj b/dists/msvc7/kyra.vcproj
index d547288d21..18b42878bf 100644
--- a/dists/msvc7/kyra.vcproj
+++ b/dists/msvc7/kyra.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="kyra_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -193,12 +200,24 @@
RelativePath="..\..\engines\kyra\kyra_v2.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\lol.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\lol.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\resource.cpp">
</File>
<File
RelativePath="..\..\engines\kyra\resource.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\resource_intern.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\resource_intern.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\saveload.cpp">
</File>
<File
@@ -244,6 +263,12 @@
RelativePath="..\..\engines\kyra\screen_lok.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\screen_lol.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\screen_lol.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\screen_mr.cpp">
</File>
<File
diff --git a/dists/msvc7/lure.vcproj b/dists/msvc7/lure.vcproj
index 7a1696f509..3e772218bc 100644
--- a/dists/msvc7/lure.vcproj
+++ b/dists/msvc7/lure.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="lure_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/m4.vcproj b/dists/msvc7/m4.vcproj
index 11b2169ccb..43a563abae 100644
--- a/dists/msvc7/m4.vcproj
+++ b/dists/msvc7/m4.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="m4_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/made.vcproj b/dists/msvc7/made.vcproj
index 757d46aa23..f0bec886ca 100644
--- a/dists/msvc7/made.vcproj
+++ b/dists/msvc7/made.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="made_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/parallaction.vcproj b/dists/msvc7/parallaction.vcproj
index 2dac8737c2..6547c6ccf6 100644
--- a/dists/msvc7/parallaction.vcproj
+++ b/dists/msvc7/parallaction.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="parallaction_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -205,6 +212,9 @@
RelativePath="..\..\engines\parallaction\saveload.cpp">
</File>
<File
+ RelativePath="..\..\engines\parallaction\saveload.h">
+ </File>
+ <File
RelativePath="..\..\engines\parallaction\sound.cpp">
</File>
<File
diff --git a/dists/msvc7/queen.vcproj b/dists/msvc7/queen.vcproj
index 499a048660..bc8987ec9d 100644
--- a/dists/msvc7/queen.vcproj
+++ b/dists/msvc7/queen.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="queen_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/saga.vcproj b/dists/msvc7/saga.vcproj
index 1a1cb29555..6b19ea2503 100644
--- a/dists/msvc7/saga.vcproj
+++ b/dists/msvc7/saga.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="Windows-1252"?>
+<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.00"
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="saga_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/scumm.vcproj b/dists/msvc7/scumm.vcproj
index 56f78692cc..397d6ef68b 100644
--- a/dists/msvc7/scumm.vcproj
+++ b/dists/msvc7/scumm.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="scumm_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -105,12 +112,6 @@
RelativePath="..\..\engines\scumm\smush\channel.h">
</File>
<File
- RelativePath="..\..\engines\scumm\smush\chunk.cpp">
- </File>
- <File
- RelativePath="..\..\engines\scumm\smush\chunk.h">
- </File>
- <File
RelativePath="..\..\engines\scumm\smush\chunk_type.h">
</File>
<File
@@ -553,9 +554,6 @@
RelativePath="..\..\engines\scumm\string.cpp">
</File>
<File
- RelativePath="..\..\engines\scumm\thumbnail.cpp">
- </File>
- <File
RelativePath="..\..\engines\scumm\usage_bits.cpp">
</File>
<File
diff --git a/dists/msvc7/scummvm.vcproj b/dists/msvc7/scummvm.vcproj
index 884cd58a5a..dd982dea23 100644
--- a/dists/msvc7/scummvm.vcproj
+++ b/dists/msvc7/scummvm.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,11 +29,14 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -68,14 +72,16 @@
IntermediateDirectory="scummvm_Release"
ConfigurationType="1"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
StringPooling="TRUE"
MinimalRebuild="FALSE"
@@ -88,12 +94,13 @@
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib"
+ AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib tinsel_release/tinsel.lib"
OutputFile="$(OutDir)/scummvm.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
@@ -130,12 +137,6 @@
RelativePath="..\..\base\commandLine.h">
</File>
<File
- RelativePath="..\..\base\game.cpp">
- </File>
- <File
- RelativePath="..\..\base\game.h">
- </File>
- <File
RelativePath="..\..\base\internal_version.h">
</File>
<File
@@ -169,6 +170,12 @@
RelativePath="..\..\common\algorithm.h">
</File>
<File
+ RelativePath="..\..\common\archive.cpp">
+ </File>
+ <File
+ RelativePath="..\..\common\archive.h">
+ </File>
+ <File
RelativePath="..\..\common\array.h">
</File>
<File
@@ -259,6 +266,9 @@
RelativePath="..\..\common\ptr.h">
</File>
<File
+ RelativePath="..\..\common\queue.h">
+ </File>
+ <File
RelativePath="..\..\common\rect.h">
</File>
<File
@@ -642,9 +652,6 @@
</Filter>
<Filter
Name="backends">
- <File
- RelativePath="..\..\backends\intern.h">
- </File>
<Filter
Name="sdl">
<File
@@ -680,11 +687,20 @@
<Filter
Name="fs">
<File
+ RelativePath="..\..\backends\fs\abstract-fs.cpp">
+ </File>
+ <File
RelativePath="..\..\backends\fs\abstract-fs.h">
</File>
<File
RelativePath="..\..\backends\fs\fs-factory.h">
</File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.cpp">
+ </File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.h">
+ </File>
<Filter
Name="windows">
<File
@@ -965,6 +981,12 @@
<File
RelativePath="..\..\graphics\surface.h">
</File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.cpp">
+ </File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.h">
+ </File>
<Filter
Name="scaler">
<File
@@ -1041,7 +1063,7 @@
RelativePath="..\..\graphics\scaler\scalebit.h">
</File>
<File
- RelativePath="..\..\graphics\scaler\thumbnail.cpp">
+ RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp">
</File>
</Filter>
<Filter
@@ -1063,12 +1085,24 @@
<Filter
Name="engines">
<File
+ RelativePath="..\..\engines\dialogs.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\dialogs.h">
+ </File>
+ <File
RelativePath="..\..\engines\engine.cpp">
</File>
<File
RelativePath="..\..\engines\engine.h">
</File>
<File
+ RelativePath="..\..\engines\game.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\game.h">
+ </File>
+ <File
RelativePath="..\..\engines\metaengine.h">
</File>
</Filter>
diff --git a/dists/msvc7/sky.vcproj b/dists/msvc7/sky.vcproj
index 188cdb0505..16a8d000d9 100644
--- a/dists/msvc7/sky.vcproj
+++ b/dists/msvc7/sky.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="sky_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/sword1.vcproj b/dists/msvc7/sword1.vcproj
index 3dd3388328..f312bfd8c0 100644
--- a/dists/msvc7/sword1.vcproj
+++ b/dists/msvc7/sword1.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="sword1_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/sword2.vcproj b/dists/msvc7/sword2.vcproj
index 07382a5c0a..c852510087 100644
--- a/dists/msvc7/sword2.vcproj
+++ b/dists/msvc7/sword2.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,14 +61,16 @@
IntermediateDirectory="sword2_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc7/tinsel.vcproj b/dists/msvc7/tinsel.vcproj
new file mode 100644
index 0000000000..c1709e2b61
--- /dev/null
+++ b/dists/msvc7/tinsel.vcproj
@@ -0,0 +1,349 @@
+<?xml version="1.0" encoding="windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="tinsel"
+ ProjectGUID="{22AA7760-2C91-11DD-BD0B-0800200C9A66}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="tinsel_Debug"
+ IntermediateDirectory="tinsel_Debug"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
+ Optimization="0"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
+ PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="TRUE"
+ EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="TRUE"
+ SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/tinsel.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="tinsel_Release"
+ IntermediateDirectory="tinsel_Release"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="../../;../../engines"
+ PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
+ StringPooling="TRUE"
+ ExceptionHandling="TRUE"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="FALSE"
+ EnableFunctionLevelLinking="FALSE"
+ DisableLanguageExtensions="FALSE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="TRUE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/tinsel.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\engines\tinsel\actors.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\actors.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\anim.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\anim.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\background.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\background.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\bg.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cliprect.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cliprect.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\config.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\config.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\coroutine.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cursor.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cursor.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\debugger.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\debugger.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\detection.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\dw.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\effect.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\events.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\events.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\faders.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\faders.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\film.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\font.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\font.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\graphics.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\graphics.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\handle.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\handle.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\heapmem.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\heapmem.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\inventory.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\inventory.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\mareels.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\move.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\move.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\multiobj.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\multiobj.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\music.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\music.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\object.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\object.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\palette.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\palette.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pcode.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pcode.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pdisplay.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pid.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\play.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\polygons.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\polygons.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\rince.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\rince.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\saveload.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\savescn.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\savescn.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scene.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scene.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sched.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sched.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scn.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scn.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scroll.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scroll.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\serializer.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sound.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sound.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\strres.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\strres.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\text.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\text.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\timers.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\timers.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinlib.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinlib.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinsel.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinsel.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\token.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\token.h">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/dists/msvc7/touche.vcproj b/dists/msvc7/touche.vcproj
index 7b81ab2052..983e848226 100644
--- a/dists/msvc7/touche.vcproj
+++ b/dists/msvc7/touche.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -57,12 +61,14 @@
IntermediateDirectory="touche_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -75,6 +81,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/agi.vcproj b/dists/msvc71/agi.vcproj
index dc4697a4fd..de73c01ff4 100644
--- a/dists/msvc71/agi.vcproj
+++ b/dists/msvc71/agi.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="agi_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/agos.vcproj b/dists/msvc71/agos.vcproj
index 7f01df5f68..3bdde3b847 100644
--- a/dists/msvc71/agos.vcproj
+++ b/dists/msvc71/agos.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="agos_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/cine.vcproj b/dists/msvc71/cine.vcproj
index cdea3e9fb8..8fd43a55a8 100644
--- a/dists/msvc71/cine.vcproj
+++ b/dists/msvc71/cine.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="cine_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/cruise.vcproj b/dists/msvc71/cruise.vcproj
index 53ed72f60e..a03a63ae4d 100644
--- a/dists/msvc71/cruise.vcproj
+++ b/dists/msvc71/cruise.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="cruise_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -159,9 +166,6 @@
RelativePath="..\..\engines\cruise\dataLoader.h">
</File>
<File
- RelativePath="..\..\engines\cruise\decompiler.cpp">
- </File>
- <File
RelativePath="..\..\engines\cruise\delphine-unpack.cpp">
</File>
<File
diff --git a/dists/msvc71/drascula.vcproj b/dists/msvc71/drascula.vcproj
index 9160a02bbf..72eecd1a3f 100644
--- a/dists/msvc71/drascula.vcproj
+++ b/dists/msvc71/drascula.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="drascula_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/gob.vcproj b/dists/msvc71/gob.vcproj
index 3d6408cdf5..972e8ab12e 100644
--- a/dists/msvc71/gob.vcproj
+++ b/dists/msvc71/gob.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="gob_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -282,6 +289,12 @@
RelativePath="..\..\engines\gob\inter_v4.cpp">
</File>
<File
+ RelativePath="..\..\engines\gob\inter_v5.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\gob\inter_v6.cpp">
+ </File>
+ <File
RelativePath="..\..\engines\gob\map.cpp">
</File>
<File
@@ -378,6 +391,9 @@
RelativePath="..\..\engines\gob\video_v2.cpp">
</File>
<File
+ RelativePath="..\..\engines\gob\video_v6.cpp">
+ </File>
+ <File
RelativePath="..\..\engines\gob\videoplayer.cpp">
</File>
<File
diff --git a/dists/msvc71/igor.vcproj b/dists/msvc71/igor.vcproj
index 20324afba4..887cfe0c17 100644
--- a/dists/msvc71/igor.vcproj
+++ b/dists/msvc71/igor.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="igor_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/kyra.vcproj b/dists/msvc71/kyra.vcproj
index f37b1d85fc..b70f187ae9 100644
--- a/dists/msvc71/kyra.vcproj
+++ b/dists/msvc71/kyra.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="kyra_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -207,12 +214,24 @@
RelativePath="..\..\engines\kyra\kyra_v2.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\lol.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\lol.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\resource.cpp">
</File>
<File
RelativePath="..\..\engines\kyra\resource.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\resource_intern.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\resource_intern.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\saveload.cpp">
</File>
<File
@@ -258,6 +277,12 @@
RelativePath="..\..\engines\kyra\screen_lok.h">
</File>
<File
+ RelativePath="..\..\engines\kyra\screen_lol.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\screen_lol.h">
+ </File>
+ <File
RelativePath="..\..\engines\kyra\screen_mr.cpp">
</File>
<File
diff --git a/dists/msvc71/lure.vcproj b/dists/msvc71/lure.vcproj
index 3ca3116962..4bda34c098 100644
--- a/dists/msvc71/lure.vcproj
+++ b/dists/msvc71/lure.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="lure_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/m4.vcproj b/dists/msvc71/m4.vcproj
index d7aefaa439..26d18c62a1 100644
--- a/dists/msvc71/m4.vcproj
+++ b/dists/msvc71/m4.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="m4_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/made.vcproj b/dists/msvc71/made.vcproj
index 5d0dd621e8..a21ab9cf62 100644
--- a/dists/msvc71/made.vcproj
+++ b/dists/msvc71/made.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="made_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/parallaction.vcproj b/dists/msvc71/parallaction.vcproj
index c72fb68234..22a564be40 100644
--- a/dists/msvc71/parallaction.vcproj
+++ b/dists/msvc71/parallaction.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="parallaction_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -219,6 +226,9 @@
RelativePath="..\..\engines\parallaction\saveload.cpp">
</File>
<File
+ RelativePath="..\..\engines\parallaction\saveload.h">
+ </File>
+ <File
RelativePath="..\..\engines\parallaction\sound.cpp">
</File>
<File
diff --git a/dists/msvc71/queen.vcproj b/dists/msvc71/queen.vcproj
index eefa686767..063425c52a 100644
--- a/dists/msvc71/queen.vcproj
+++ b/dists/msvc71/queen.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="queen_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/saga.vcproj b/dists/msvc71/saga.vcproj
index 388dd64ff2..588ad2873c 100644
--- a/dists/msvc71/saga.vcproj
+++ b/dists/msvc71/saga.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="Windows-1252"?>
+<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="saga_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/scumm.vcproj b/dists/msvc71/scumm.vcproj
index 661cc1fa19..b70e50bb05 100644
--- a/dists/msvc71/scumm.vcproj
+++ b/dists/msvc71/scumm.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="scumm_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -119,12 +126,6 @@
RelativePath="..\..\engines\scumm\smush\channel.h">
</File>
<File
- RelativePath="..\..\engines\scumm\smush\chunk.cpp">
- </File>
- <File
- RelativePath="..\..\engines\scumm\smush\chunk.h">
- </File>
- <File
RelativePath="..\..\engines\scumm\smush\chunk_type.h">
</File>
<File
@@ -567,9 +568,6 @@
RelativePath="..\..\engines\scumm\string.cpp">
</File>
<File
- RelativePath="..\..\engines\scumm\thumbnail.cpp">
- </File>
- <File
RelativePath="..\..\engines\scumm\usage_bits.cpp">
</File>
<File
diff --git a/dists/msvc71/scummvm.vcproj b/dists/msvc71/scummvm.vcproj
index 6234c89dd5..0648d5a43f 100644
--- a/dists/msvc71/scummvm.vcproj
+++ b/dists/msvc71/scummvm.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,11 +29,14 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -74,14 +78,16 @@
IntermediateDirectory="scummvm_Release"
ConfigurationType="1"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
StringPooling="TRUE"
MinimalRebuild="FALSE"
@@ -94,12 +100,13 @@
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib"
+ AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib tinsel_release/tinsel.lib"
OutputFile="$(OutDir)/scummvm.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
@@ -144,12 +151,6 @@
RelativePath="..\..\base\commandLine.h">
</File>
<File
- RelativePath="..\..\base\game.cpp">
- </File>
- <File
- RelativePath="..\..\base\game.h">
- </File>
- <File
RelativePath="..\..\base\internal_version.h">
</File>
<File
@@ -183,6 +184,12 @@
RelativePath="..\..\common\algorithm.h">
</File>
<File
+ RelativePath="..\..\common\archive.cpp">
+ </File>
+ <File
+ RelativePath="..\..\common\archive.h">
+ </File>
+ <File
RelativePath="..\..\common\array.h">
</File>
<File
@@ -273,6 +280,9 @@
RelativePath="..\..\common\ptr.h">
</File>
<File
+ RelativePath="..\..\common\queue.h">
+ </File>
+ <File
RelativePath="..\..\common\rect.h">
</File>
<File
@@ -656,9 +666,6 @@
</Filter>
<Filter
Name="backends">
- <File
- RelativePath="..\..\backends\intern.h">
- </File>
<Filter
Name="sdl">
<File
@@ -694,11 +701,20 @@
<Filter
Name="fs">
<File
+ RelativePath="..\..\backends\fs\abstract-fs.cpp">
+ </File>
+ <File
RelativePath="..\..\backends\fs\abstract-fs.h">
</File>
<File
RelativePath="..\..\backends\fs\fs-factory.h">
</File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.cpp">
+ </File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.h">
+ </File>
<Filter
Name="windows">
<File
@@ -979,6 +995,12 @@
<File
RelativePath="..\..\graphics\surface.h">
</File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.cpp">
+ </File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.h">
+ </File>
<Filter
Name="scaler">
<File
@@ -1055,7 +1077,7 @@
RelativePath="..\..\graphics\scaler\scalebit.h">
</File>
<File
- RelativePath="..\..\graphics\scaler\thumbnail.cpp">
+ RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp">
</File>
</Filter>
<Filter
@@ -1077,12 +1099,24 @@
<Filter
Name="engines">
<File
+ RelativePath="..\..\engines\dialogs.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\dialogs.h">
+ </File>
+ <File
RelativePath="..\..\engines\engine.cpp">
</File>
<File
RelativePath="..\..\engines\engine.h">
</File>
<File
+ RelativePath="..\..\engines\game.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\game.h">
+ </File>
+ <File
RelativePath="..\..\engines\metaengine.h">
</File>
</Filter>
diff --git a/dists/msvc71/sky.vcproj b/dists/msvc71/sky.vcproj
index cb8303a6b2..b49534babb 100644
--- a/dists/msvc71/sky.vcproj
+++ b/dists/msvc71/sky.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="sky_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/sword1.vcproj b/dists/msvc71/sword1.vcproj
index 602a5a9529..953d6ca88f 100644
--- a/dists/msvc71/sword1.vcproj
+++ b/dists/msvc71/sword1.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="sword1_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/sword2.vcproj b/dists/msvc71/sword2.vcproj
index f97da0ea91..d758641d5b 100644
--- a/dists/msvc71/sword2.vcproj
+++ b/dists/msvc71/sword2.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,14 +67,16 @@
IntermediateDirectory="sword2_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="TRUE"
ExceptionHandling="TRUE"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc71/tinsel.vcproj b/dists/msvc71/tinsel.vcproj
new file mode 100644
index 0000000000..b8475b5866
--- /dev/null
+++ b/dists/msvc71/tinsel.vcproj
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="tinsel"
+ ProjectGUID="{22AA7760-2C91-11DD-BD0B-0800200C9A66}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="tinsel_Debug"
+ IntermediateDirectory="tinsel_Debug"
+ ConfigurationType="4"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
+ Optimization="0"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
+ PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="TRUE"
+ EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="TRUE"
+ SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/tinsel.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="tinsel_Release"
+ IntermediateDirectory="tinsel_Release"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="TRUE"
+ AdditionalIncludeDirectories="../../;../../engines"
+ PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
+ StringPooling="TRUE"
+ ExceptionHandling="TRUE"
+ RuntimeLibrary="0"
+ BufferSecurityCheck="FALSE"
+ EnableFunctionLevelLinking="FALSE"
+ DisableLanguageExtensions="FALSE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ WarnAsError="TRUE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/tinsel.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\engines\tinsel\actors.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\actors.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\anim.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\anim.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\background.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\background.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\bg.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cliprect.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cliprect.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\config.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\config.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\coroutine.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cursor.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\cursor.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\debugger.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\debugger.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\detection.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\dw.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\effect.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\events.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\events.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\faders.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\faders.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\film.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\font.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\font.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\graphics.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\graphics.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\handle.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\handle.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\heapmem.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\heapmem.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\inventory.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\inventory.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\mareels.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\move.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\move.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\multiobj.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\multiobj.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\music.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\music.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\object.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\object.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\palette.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\palette.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pcode.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pcode.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pdisplay.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\pid.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\play.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\polygons.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\polygons.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\rince.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\rince.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\saveload.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\savescn.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\savescn.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scene.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scene.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sched.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sched.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scn.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scn.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scroll.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\scroll.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\serializer.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sound.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\sound.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\strres.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\strres.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\text.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\text.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\timers.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\timers.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinlib.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinlib.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinsel.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\tinsel.h">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\token.cpp">
+ </File>
+ <File
+ RelativePath="..\..\engines\tinsel\token.h">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/dists/msvc71/touche.vcproj b/dists/msvc71/touche.vcproj
index e40e861542..bd309c5ce3 100644
--- a/dists/msvc71/touche.vcproj
+++ b/dists/msvc71/touche.vcproj
@@ -20,7 +20,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
@@ -28,10 +29,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
+ DisableLanguageExtensions="FALSE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
SuppressStartupBanner="FALSE"
+ Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
@@ -63,12 +67,14 @@
IntermediateDirectory="touche_Release"
ConfigurationType="4"
CharacterSet="2"
- WholeProgramOptimization="FALSE">
+ WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="TRUE"
+ FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -81,6 +87,7 @@
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
+ WarnAsError="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
diff --git a/dists/msvc8/agi.vcproj b/dists/msvc8/agi.vcproj
index 990cf155e0..08d734221b 100644
--- a/dists/msvc8/agi.vcproj
+++ b/dists/msvc8/agi.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/agos.vcproj b/dists/msvc8/agos.vcproj
index 6a7f937676..3fd581a45b 100644
--- a/dists/msvc8/agos.vcproj
+++ b/dists/msvc8/agos.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/cine.vcproj b/dists/msvc8/cine.vcproj
index cd8a6673db..22061d57c0 100644
--- a/dists/msvc8/cine.vcproj
+++ b/dists/msvc8/cine.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/cruise.vcproj b/dists/msvc8/cruise.vcproj
index f183d07ee3..d8c81b2a01 100644
--- a/dists/msvc8/cruise.vcproj
+++ b/dists/msvc8/cruise.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -225,10 +231,6 @@
>
</File>
<File
- RelativePath="..\..\engines\cruise\decompiler.cpp"
- >
- </File>
- <File
RelativePath="..\..\engines\cruise\delphine-unpack.cpp"
>
</File>
diff --git a/dists/msvc8/drascula.vcproj b/dists/msvc8/drascula.vcproj
index 0867377f31..e096b33239 100644
--- a/dists/msvc8/drascula.vcproj
+++ b/dists/msvc8/drascula.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/gob.vcproj b/dists/msvc8/gob.vcproj
index c178caf8be..982f7e3f0c 100644
--- a/dists/msvc8/gob.vcproj
+++ b/dists/msvc8/gob.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,20 +114,23 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
DebugInformationFormat="0"
/>
<Tool
@@ -389,6 +395,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\gob\inter_v5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\gob\inter_v6.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\gob\map.cpp"
>
</File>
@@ -517,6 +531,10 @@
>
</File>
<File
+ RelativePath="..\..\engines\gob\video_v6.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\gob\videoplayer.cpp"
>
</File>
diff --git a/dists/msvc8/igor.vcproj b/dists/msvc8/igor.vcproj
index f2470ee633..dbfc5cc6bc 100644
--- a/dists/msvc8/igor.vcproj
+++ b/dists/msvc8/igor.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/kyra.vcproj b/dists/msvc8/kyra.vcproj
index c99abdc5bc..8798677947 100644
--- a/dists/msvc8/kyra.vcproj
+++ b/dists/msvc8/kyra.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -289,6 +295,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\lol.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\lol.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\resource.cpp"
>
</File>
@@ -297,6 +311,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\resource_intern.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\resource_intern.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\saveload.cpp"
>
</File>
@@ -357,6 +379,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\screen_lol.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\screen_lol.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\screen_mr.cpp"
>
</File>
diff --git a/dists/msvc8/lure.vcproj b/dists/msvc8/lure.vcproj
index 887a8d4fb0..5102e74117 100644
--- a/dists/msvc8/lure.vcproj
+++ b/dists/msvc8/lure.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/m4.vcproj b/dists/msvc8/m4.vcproj
index a3f286bff3..9d27e60132 100644
--- a/dists/msvc8/m4.vcproj
+++ b/dists/msvc8/m4.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/made.vcproj b/dists/msvc8/made.vcproj
index b3c309b334..13b32b61d5 100644
--- a/dists/msvc8/made.vcproj
+++ b/dists/msvc8/made.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/parallaction.vcproj b/dists/msvc8/parallaction.vcproj
index e268fe1e6b..ddb0a13b46 100644
--- a/dists/msvc8/parallaction.vcproj
+++ b/dists/msvc8/parallaction.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -305,6 +311,10 @@
>
</File>
<File
+ RelativePath="..\..\engines\parallaction\saveload.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\parallaction\sound.cpp"
>
</File>
diff --git a/dists/msvc8/queen.vcproj b/dists/msvc8/queen.vcproj
index 6be3251d8c..eec37976bf 100644
--- a/dists/msvc8/queen.vcproj
+++ b/dists/msvc8/queen.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/saga.vcproj b/dists/msvc8/saga.vcproj
index 79f7d35fb5..bd38dbbfca 100644
--- a/dists/msvc8/saga.vcproj
+++ b/dists/msvc8/saga.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="Windows-1252"?>
+<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/scumm.vcproj b/dists/msvc8/scumm.vcproj
index 42a4ff6993..021df227e8 100644
--- a/dists/msvc8/scumm.vcproj
+++ b/dists/msvc8/scumm.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,10 +114,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
@@ -173,14 +178,6 @@
>
</File>
<File
- RelativePath="..\..\engines\scumm\smush\chunk.cpp"
- >
- </File>
- <File
- RelativePath="..\..\engines\scumm\smush\chunk.h"
- >
- </File>
- <File
RelativePath="..\..\engines\scumm\smush\chunk_type.h"
>
</File>
@@ -770,10 +767,6 @@
>
</File>
<File
- RelativePath="..\..\engines\scumm\thumbnail.cpp"
- >
- </File>
- <File
RelativePath="..\..\engines\scumm\usage_bits.cpp"
>
</File>
diff --git a/dists/msvc8/scummvm.vcproj b/dists/msvc8/scummvm.vcproj
index e1a872e191..ceb98da482 100644
--- a/dists/msvc8/scummvm.vcproj
+++ b/dists/msvc8/scummvm.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,12 +50,14 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -129,10 +132,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
StringPooling="true"
MinimalRebuild="false"
@@ -140,6 +145,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
@@ -158,7 +164,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib"
+ AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib tinsel_release/tinsel.lib"
OutputFile="$(OutDir)/scummvm.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
@@ -211,14 +217,6 @@
>
</File>
<File
- RelativePath="..\..\base\game.cpp"
- >
- </File>
- <File
- RelativePath="..\..\base\game.h"
- >
- </File>
- <File
RelativePath="..\..\base\internal_version.h"
>
</File>
@@ -263,6 +261,14 @@
>
</File>
<File
+ RelativePath="..\..\common\archive.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\archive.h"
+ >
+ </File>
+ <File
RelativePath="..\..\common\array.h"
>
</File>
@@ -903,10 +909,6 @@
<Filter
Name="backends"
>
- <File
- RelativePath="..\..\backends\intern.h"
- >
- </File>
<Filter
Name="sdl"
>
@@ -953,6 +955,10 @@
Name="fs"
>
<File
+ RelativePath="..\..\backends\fs\abstract-fs.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\backends\fs\abstract-fs.h"
>
</File>
@@ -960,6 +966,14 @@
RelativePath="..\..\backends\fs\fs-factory.h"
>
</File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.h"
+ >
+ </File>
<Filter
Name="windows"
>
@@ -1433,6 +1447,14 @@
RelativePath="..\..\graphics\surface.h"
>
</File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.h"
+ >
+ </File>
<Filter
Name="scaler"
>
@@ -1533,7 +1555,7 @@
>
</File>
<File
- RelativePath="..\..\graphics\scaler\thumbnail.cpp"
+ RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp"
>
</File>
</Filter>
@@ -1562,6 +1584,14 @@
Name="engines"
>
<File
+ RelativePath="..\..\engines\dialogs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\dialogs.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\engine.cpp"
>
</File>
@@ -1570,6 +1600,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\game.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\game.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\metaengine.h"
>
</File>
diff --git a/dists/msvc8/sky.vcproj b/dists/msvc8/sky.vcproj
index b2e77699e0..ffed869c8b 100644
--- a/dists/msvc8/sky.vcproj
+++ b/dists/msvc8/sky.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,10 +114,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
diff --git a/dists/msvc8/sword1.vcproj b/dists/msvc8/sword1.vcproj
index 689f6dc1c4..c242a42e70 100644
--- a/dists/msvc8/sword1.vcproj
+++ b/dists/msvc8/sword1.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/sword2.vcproj b/dists/msvc8/sword2.vcproj
index e68a32631e..b90f38be9f 100644
--- a/dists/msvc8/sword2.vcproj
+++ b/dists/msvc8/sword2.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -111,16 +114,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/tinsel.vcproj b/dists/msvc8/tinsel.vcproj
index cb6ba0c2e8..b5397681bb 100644
--- a/dists/msvc8/tinsel.vcproj
+++ b/dists/msvc8/tinsel.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="8.00"
+ Version="8,00"
Name="tinsel"
ProjectGUID="{22AA7760-2C91-11DD-BD0B-0800200C9A66}"
RootNamespace="tinsel"
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8/touche.vcproj b/dists/msvc8/touche.vcproj
index 0a517bb40c..d314a910da 100644
--- a/dists/msvc8/touche.vcproj
+++ b/dists/msvc8/touche.vcproj
@@ -41,7 +41,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -49,11 +50,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -113,6 +116,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -121,6 +126,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc8_to_msvc7_71.bat b/dists/msvc8_to_msvc7_71.bat
index 71d04f68a3..020a26172a 100644
--- a/dists/msvc8_to_msvc7_71.bat
+++ b/dists/msvc8_to_msvc7_71.bat
@@ -19,20 +19,14 @@ rpl -e -q "\t\tKeyword=" "\tKeyword=" msvc71\*.vcproj
rpl -e -q "\t<ToolFiles>\n\t</ToolFiles>\n" "" msvc71\*.vcproj
rpl -e -q " /wd4996" "" msvc71\*.vcproj
rpl -e -q "ExceptionHandling=\"1\"" "ExceptionHandling=\"true\"" msvc71\*.vcproj
-rpl -e -q "\t\t\t\tWarnAsError=\"false\"\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCManagedResourceCompilerTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCPreLinkEventTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCALinkTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCXDCMakeTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCBscMakeTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
rpl -e -q "\t\t\t<Tool\n\t\t\t\tName=\"VCFxCopTool\"\n\t\t\t/>\n" "" msvc71\*.vcproj
-rpl -e -q "WholeProgramOptimization=\"1\"" "WholeProgramOptimization=\"false\"" msvc71\*.vcproj
-rpl -e -q "Optimization=\"3\"" "Optimization=\"2\"" msvc71\*.vcproj
-rpl -e -q "InlineFunctionExpansion=\"2\"" "InlineFunctionExpansion=\"1\"" msvc71\*.vcproj
+rpl -e -q "WholeProgramOptimization=\"1\"" "WholeProgramOptimization=\"true\"" msvc71\*.vcproj
rpl -e -q "ExceptionHandling=\"1\"" "ExceptionHandling=\"true\"" msvc71\*.vcproj
-rpl -e -q "\t\t\t\tWarnAsError=\"true\"\n" "" msvc71\*.vcproj
-rpl -e -q "\t\t\t\tDisableLanguageExtensions=\"false\"\n" "" msvc71\*.vcproj
-rpl -e -q "\t\t\t\tEnableFunctionLevelLinking=\"false\"\n" "\t\t\t\tEnableFunctionLevelLinking=\"false\"\n\t\t\t\tDisableLanguageExtensions=\"false\"\n" msvc71\*.vcproj
rem Change multi-line XML closing tags to single line
rpl -e -q "\"\n\t\0x3e\n" "\"\0x3e\n" msvc71\*.vcproj
rpl -e -q "\"\n\t/\0x3e\n" "\"/\0x3e\n" msvc71\*.vcproj
diff --git a/dists/msvc9/agi.vcproj b/dists/msvc9/agi.vcproj
index d0d93bb743..de79be933d 100644
--- a/dists/msvc9/agi.vcproj
+++ b/dists/msvc9/agi.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/agos.vcproj b/dists/msvc9/agos.vcproj
index 6cc268c2f8..a584d8719a 100644
--- a/dists/msvc9/agos.vcproj
+++ b/dists/msvc9/agos.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/cine.vcproj b/dists/msvc9/cine.vcproj
index c01508ff9a..194e792dfa 100644
--- a/dists/msvc9/cine.vcproj
+++ b/dists/msvc9/cine.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/cruise.vcproj b/dists/msvc9/cruise.vcproj
index 19a96eb7be..c4cd6195eb 100644
--- a/dists/msvc9/cruise.vcproj
+++ b/dists/msvc9/cruise.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -226,10 +232,6 @@
>
</File>
<File
- RelativePath="..\..\engines\cruise\decompiler.cpp"
- >
- </File>
- <File
RelativePath="..\..\engines\cruise\delphine-unpack.cpp"
>
</File>
diff --git a/dists/msvc9/drascula.vcproj b/dists/msvc9/drascula.vcproj
index 45a75cb7a2..a0ed0eaa09 100644
--- a/dists/msvc9/drascula.vcproj
+++ b/dists/msvc9/drascula.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/gob.vcproj b/dists/msvc9/gob.vcproj
index e6c55519b0..0ebeb75f20 100644
--- a/dists/msvc9/gob.vcproj
+++ b/dists/msvc9/gob.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,20 +115,23 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
DebugInformationFormat="0"
/>
<Tool
@@ -390,6 +396,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\gob\inter_v5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\gob\inter_v6.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\gob\map.cpp"
>
</File>
@@ -518,6 +532,10 @@
>
</File>
<File
+ RelativePath="..\..\engines\gob\video_v6.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\gob\videoplayer.cpp"
>
</File>
diff --git a/dists/msvc9/igor.vcproj b/dists/msvc9/igor.vcproj
index ff2579a97d..b812db787c 100644
--- a/dists/msvc9/igor.vcproj
+++ b/dists/msvc9/igor.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/kyra.vcproj b/dists/msvc9/kyra.vcproj
index f56a2733b5..e65d02f5cd 100644
--- a/dists/msvc9/kyra.vcproj
+++ b/dists/msvc9/kyra.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -290,6 +296,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\lol.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\lol.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\resource.cpp"
>
</File>
@@ -298,6 +312,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\resource_intern.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\resource_intern.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\saveload.cpp"
>
</File>
@@ -358,6 +380,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\kyra\screen_lol.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\kyra\screen_lol.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\kyra\screen_mr.cpp"
>
</File>
diff --git a/dists/msvc9/lure.vcproj b/dists/msvc9/lure.vcproj
index 2745b0a2bc..2915a69dbc 100644
--- a/dists/msvc9/lure.vcproj
+++ b/dists/msvc9/lure.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/m4.vcproj b/dists/msvc9/m4.vcproj
index 786b014e90..89cf4cef78 100644
--- a/dists/msvc9/m4.vcproj
+++ b/dists/msvc9/m4.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/made.vcproj b/dists/msvc9/made.vcproj
index a96ae262cb..880b484be3 100644
--- a/dists/msvc9/made.vcproj
+++ b/dists/msvc9/made.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/parallaction.vcproj b/dists/msvc9/parallaction.vcproj
index f901976c37..5c91264919 100644
--- a/dists/msvc9/parallaction.vcproj
+++ b/dists/msvc9/parallaction.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -306,6 +312,10 @@
>
</File>
<File
+ RelativePath="..\..\engines\parallaction\saveload.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\parallaction\sound.cpp"
>
</File>
diff --git a/dists/msvc9/queen.vcproj b/dists/msvc9/queen.vcproj
index d8fb96ac0b..384cede45c 100644
--- a/dists/msvc9/queen.vcproj
+++ b/dists/msvc9/queen.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/saga.vcproj b/dists/msvc9/saga.vcproj
index 9675dda2e9..241bd5b498 100644
--- a/dists/msvc9/saga.vcproj
+++ b/dists/msvc9/saga.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="Windows-1252"?>
+<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/scumm.vcproj b/dists/msvc9/scumm.vcproj
index 230102db35..afb79cc3b6 100644
--- a/dists/msvc9/scumm.vcproj
+++ b/dists/msvc9/scumm.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,10 +115,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_SCUMM_7_8;ENABLE_HE;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
@@ -174,14 +179,6 @@
>
</File>
<File
- RelativePath="..\..\engines\scumm\smush\chunk.cpp"
- >
- </File>
- <File
- RelativePath="..\..\engines\scumm\smush\chunk.h"
- >
- </File>
- <File
RelativePath="..\..\engines\scumm\smush\chunk_type.h"
>
</File>
@@ -771,10 +768,6 @@
>
</File>
<File
- RelativePath="..\..\engines\scumm\thumbnail.cpp"
- >
- </File>
- <File
RelativePath="..\..\engines\scumm\usage_bits.cpp"
>
</File>
diff --git a/dists/msvc9/scummvm.vcproj b/dists/msvc9/scummvm.vcproj
index 31270652df..06545097f6 100644
--- a/dists/msvc9/scummvm.vcproj
+++ b/dists/msvc9/scummvm.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_NASM;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,12 +51,14 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -132,10 +135,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2;USE_MT32EMU;ENABLE_AGI;ENABLE_AGOS;ENABLE_CINE;ENABLE_CRUISE;ENABLE_DRASCULA;ENABLE_GOB;ENABLE_IGOR;ENABLE_KYRA;ENABLE_LURE;ENABLE_M4;ENABLE_MADE;ENABLE_PARALLACTION;ENABLE_QUEEN;ENABLE_SAGA;ENABLE_SCUMM;ENABLE_SKY;ENABLE_SWORD1;ENABLE_SWORD2;ENABLE_TOUCHE;ENABLE_SCUMM_7_8;ENABLE_HE;ENABLE_TINSEL"
StringPooling="true"
MinimalRebuild="false"
@@ -143,6 +148,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
RuntimeTypeInfo="true"
UsePrecompiledHeader="0"
@@ -161,7 +167,7 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib"
+ AdditionalDependencies="winmm.lib sdl.lib zlib.lib libmad.lib vorbisfile_static.lib vorbis_static.lib ogg_static.lib libmpeg2.lib saga_release/saga.lib agi_release/agi.lib sword1_release/sword1.lib sword2_release/sword2.lib lure_release/lure.lib cine_release/cine.lib cruise_release/cruise.lib igor_release/igor.lib kyra_release/kyra.lib gob_release/gob.lib queen_release/queen.lib scumm_release/scumm.lib agos_release/agos.lib sky_release/sky.lib drascula_release/drascula.lib parallaction_release/parallaction.lib m4_release/m4.lib made_release/made.lib tinsel_release/tinsel.lib"
OutputFile="$(OutDir)/scummvm.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
@@ -216,14 +222,6 @@
>
</File>
<File
- RelativePath="..\..\base\game.cpp"
- >
- </File>
- <File
- RelativePath="..\..\base\game.h"
- >
- </File>
- <File
RelativePath="..\..\base\internal_version.h"
>
</File>
@@ -268,6 +266,14 @@
>
</File>
<File
+ RelativePath="..\..\common\archive.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\archive.h"
+ >
+ </File>
+ <File
RelativePath="..\..\common\array.h"
>
</File>
@@ -388,6 +394,10 @@
>
</File>
<File
+ RelativePath="..\..\common\queue.h"
+ >
+ </File>
+ <File
RelativePath="..\..\common\rect.h"
>
</File>
@@ -896,10 +906,6 @@
<Filter
Name="backends"
>
- <File
- RelativePath="..\..\backends\intern.h"
- >
- </File>
<Filter
Name="sdl"
>
@@ -946,6 +952,10 @@
Name="fs"
>
<File
+ RelativePath="..\..\backends\fs\abstract-fs.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\backends\fs\abstract-fs.h"
>
</File>
@@ -953,6 +963,14 @@
RelativePath="..\..\backends\fs\fs-factory.h"
>
</File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\backends\fs\stdiostream.h"
+ >
+ </File>
<Filter
Name="windows"
>
@@ -1326,6 +1344,14 @@
RelativePath="..\..\graphics\surface.h"
>
</File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\graphics\thumbnail.h"
+ >
+ </File>
<Filter
Name="scaler"
>
@@ -1426,7 +1452,7 @@
>
</File>
<File
- RelativePath="..\..\graphics\scaler\thumbnail.cpp"
+ RelativePath="..\..\graphics\scaler\thumbnail_intern.cpp"
>
</File>
</Filter>
@@ -1455,6 +1481,14 @@
Name="engines"
>
<File
+ RelativePath="..\..\engines\dialogs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\dialogs.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\engine.cpp"
>
</File>
@@ -1463,6 +1497,14 @@
>
</File>
<File
+ RelativePath="..\..\engines\game.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\engines\game.h"
+ >
+ </File>
+ <File
RelativePath="..\..\engines\metaengine.h"
>
</File>
diff --git a/dists/msvc9/sky.vcproj b/dists/msvc9/sky.vcproj
index d908ceb0f5..df74f239c2 100644
--- a/dists/msvc9/sky.vcproj
+++ b/dists/msvc9/sky.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,10 +115,12 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
diff --git a/dists/msvc9/sword1.vcproj b/dists/msvc9/sword1.vcproj
index dc501c3be1..d636e044e4 100644
--- a/dists/msvc9/sword1.vcproj
+++ b/dists/msvc9/sword1.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/sword2.vcproj b/dists/msvc9/sword2.vcproj
index 5f092967d7..fb8c4d8db1 100644
--- a/dists/msvc9/sword2.vcproj
+++ b/dists/msvc9/sword2.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -112,16 +115,19 @@
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
- Optimization="2"
- InlineFunctionExpansion="1"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
- AdditionalIncludeDirectories="../..;../../engines"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS;USE_MPEG2"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/tinsel.vcproj b/dists/msvc9/tinsel.vcproj
index 7623290e80..cef9683e8b 100644
--- a/dists/msvc9/tinsel.vcproj
+++ b/dists/msvc9/tinsel.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="9.00"
+ Version="9,00"
Name="tinsel"
ProjectGUID="{22AA7760-2C91-11DD-BD0B-0800200C9A66}"
RootNamespace="tinsel"
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/msvc9/touche.vcproj b/dists/msvc9/touche.vcproj
index 72b61bc00e..0ff5673c56 100644
--- a/dists/msvc9/touche.vcproj
+++ b/dists/msvc9/touche.vcproj
@@ -42,7 +42,8 @@
Name="VCCLCompilerTool"
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="0"
- AdditionalIncludeDirectories="../..;../../engines"
+ InlineFunctionExpansion="0"
+ AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
@@ -50,11 +51,13 @@
RuntimeLibrary="1"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
- WarnAsError="false"
+ WarnAsError="true"
SuppressStartupBanner="false"
+ Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
@@ -114,6 +117,8 @@
AdditionalOptions="/wd4201 /wd4512 /wd4511 /wd4100 /wd4121 /wd4310 /wd4706 /wd4127 /wd4189 /wd4702 /wd4996"
Optimization="3"
InlineFunctionExpansion="2"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
@@ -122,6 +127,7 @@
RuntimeLibrary="0"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="false"
+ DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
WarningLevel="4"
diff --git a/dists/redhat/scummvm-tools.spec b/dists/redhat/scummvm-tools.spec
index 5ca5fe9cf8..564fc17274 100644
--- a/dists/redhat/scummvm-tools.spec
+++ b/dists/redhat/scummvm-tools.spec
@@ -19,6 +19,7 @@ Source : %{name}-%{version}.tar.bz2
BuildRoot : %{_tmppath}/%{name}-%{version}-root
BuildRequires : zlib-devel
+BuildRequires : wxGTK-devel
#------------------------------------------------------------------------------
# Description
#------------------------------------------------------------------------------
@@ -36,10 +37,12 @@ make
echo -e "\t\tThis script is installed as\n\t\t"%{_datadir}/scummvm-tools/convert_dxa.sh.sample >> README
%install
-install -m755 -D encode_dxa %{buildroot}%{_bindir}/encode_dxa
+install -m755 -d %{buildroot}%{_bindir}
install -m755 -D compress_{agos,kyra,queen,saga,scumm_bun,scumm_san,scumm_sou,sword1,sword2,touche} %{buildroot}%{_bindir}
-install -m755 -D de{kyra,scumm,sword2} %{buildroot}%{_bindir}
-install -m755 -D extract_{agos,kyra,loom_tg16,mm_apple,mm_c64,mm_nes,scumm_mac,parallaction,zak_c64} %{buildroot}%{_bindir}
+install -m755 -D de{kyra,scumm,sword2,gob} %{buildroot}%{_bindir}
+install -m755 -D encode_dxa %{buildroot}%{_bindir}/encode_dxa
+install -m755 -D extract_{agos,kyra,loom_tg16,mm_apple,mm_c64,mm_nes,scumm_mac,parallaction,zak_c64,gob_stk} %{buildroot}%{_bindir}
+install -m755 -D tools_gui %{buildroot}%{_bindir}/scummvm_tools_gui
install -m644 -D convert_dxa.sh %{buildroot}%{_datadir}/scummvm-tools/convert_dxa.sh.sample
%clean
@@ -54,6 +57,7 @@ rm -Rf ${RPM_BUILD_ROOT}
%attr(0755,root,root)%{_bindir}/de*
%attr(0755,root,root)%{_bindir}/extract_*
%attr(0755,root,root)%{_bindir}/encode_dxa
+%attr(0755,root,root)%{_bindir}/scummvm_tools_gui
%attr(0644,root,root)%{_datadir}/scummvm-tools/convert_dxa.sh.sample
#------------------------------------------------------------------------------
diff --git a/dists/scummvm.6 b/dists/scummvm.6
index 1859dc119a..007e124212 100644
--- a/dists/scummvm.6
+++ b/dists/scummvm.6
@@ -12,7 +12,7 @@
.Sh DESCRIPTION
.Nm
is an interpreter that will play graphic adventure games
-based an a variety of game engines.
+based on a variety of game engines.
.Bl -tag -width Ds
.It Fl F
Force windowed mode.
@@ -172,21 +172,32 @@ Enable copy protection in SCUMM games, when ScummVM disables it
by default.
.It Fl -demo-mode
Start demo mode of Maniac Mansion.
+.It Fl -enable-gs
+Enable Roland GS mode for MIDI playback.
+.It Fl -extrapath= Ns Ar path
+Look for additional game data in
+.Ar path .
.It Fl -joystick= Ns Ar num
Enable input with joystick (default: 0 = first joystick).
.It Fl -multi-midi
Enable combination Adlib and native MIDI.
.It Fl -native-mt32
True Roland MT-32 MIDI (disable GM emulation).
+.It Fl --render-mode= Ns Ar mode
+Enable additional render
+.Ar mode
+(cga, ega, hercGreen, hercAmber, amiga).
+.It Fl -platform= Ns Ar plat
+Specify original platform of game.
.It Fl -output-rate= Ns Ar rate
Set output sample rate in Hz to
.Ar rate
(e.g. 22050).
-.It Fl -platform= Ns Ar plat
-Specify original platform of game.
.It Fl -savepath= Ns Ar path
Look for savegames in
.Ar path .
+.It Fl -soundfont= Ns Ar fILE
+Select the SoundFont for MIDI playback (only supported by some MIDI drivers).
.It Fl -talkspeed= Ns Ar speed
Set talk speed to
.Ar speed
@@ -261,6 +272,4 @@ More information can be found in the README and on the website
.Sh AUTHORS
This manual page written by Jonathan Gray <khalek at scummvm.org>.
ScummVM was written by the ScummVM team.
-See
-.Pa http://www.scummvm.org
-for more information.
+See AUTHORS file for more information.
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index 0fb2b87071..75accce341 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -27,7 +27,7 @@ BEGIN
VALUE "FileDescription", "http://www.scummvm.org/\0"
VALUE "FileVersion", "0.13.0svn\0"
VALUE "InternalName", "scummvm\0"
- VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2008 The ScummVM Team\0"
VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0"
VALUE "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0"
diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in
index 7ef88b0471..80672d54e7 100644
--- a/dists/scummvm.rc.in
+++ b/dists/scummvm.rc.in
@@ -27,7 +27,7 @@ BEGIN
VALUE "FileDescription", "http://www.scummvm.org/\0"
VALUE "FileVersion", "@VERSION@\0"
VALUE "InternalName", "scummvm\0"
- VALUE "LegalCopyright", "Copyright © 2001-2007 The ScummVM Team\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2008 The ScummVM Team\0"
VALUE "LegalTrademarks", "'SCUMM', and all SCUMM games are a TM of LucasArts. Simon The Sorcerer is a TM of AdventureSoft. Beneath a Steel Sky and Broken Sword are a TM of Revolution. Flight of the Amazon Queen is a TM of John Passfield and Steve Stamatiadis. \0"
VALUE "OriginalFilename", "scummvm.exe\0"
VALUE "ProductName", "ScummVM\0"
diff --git a/dists/wii/READMII b/dists/wii/READMII
index 4f157dffe7..c0c67eafd7 100644
--- a/dists/wii/READMII
+++ b/dists/wii/READMII
@@ -1,17 +1,23 @@
-Wii port of ScummVM README
---------------------------
+Wii/Gamecube port of ScummVM README
+-----------------------------------
features not compiled in:
- the AGI game engine
REQUIREMENTS
- - sd card
- - wiimote or gamecube controller in port 1
+ wii:
+ - sd card
+ - wiimote or gamecube controller in port 1
+
+ gamecube:
+ - sd card
+ - sd gecko adapter
+ - gamecube controller in port 1
INSTALL
- - copy the "apps" folder to the root of your sd card
+ - copy the "scummvm" folder into the "/apps" folder of your sd card
- copy your demos and/or games onto the same sd card
each game goes into its own subdirectory, do not place those under
"/apps/scummvm", and do not set the "theme" or "extra" path to that folder
@@ -20,17 +26,21 @@ INSTALL
RUN
- either use the homebrew channel, available at
+ wii:
+ either use the homebrew channel, available at
+
+ http://hbc.hackmii.com/
- http://hbc.hackmii.com/
+ or load "/apps/scummvm/boot.dol" with your favorite loader
- or load "boot.dol" with your favorite loader
+ gamecube:
+ load "/apps/scummvm/scummvm-gc.dol" with your favorite loader
CONTROLS
wiimote
- analog stick: mouse movement
+ IR: mouse movement
a: left mouse button
b: right mouse button
minus: escape
@@ -56,6 +66,21 @@ CONTROLS
dpad left: "y"
dpad right: "n"
+DISPLAY SETUP
+
+ "Graphics mode"
+ you can choose between multiple overscan options to adjust the screen size
+ used for drawing. select a higher overscan mode to get rid of black
+ borders or choose a lower overscan mode if parts of the picture get cropped
+
+ "Fullscreen mode"
+ If your wii is set to 16:9, this will stretch the picture to fullscreen.
+ Turning this option off results in black borders on the left and right
+ sides, but the aspect ratio will be kept. This option has no effect on 4:3
+ displays
+
+ you have to restart scummvm after changing one of these options
+
THANKS
shagkur and WinterMute, for devkitppc/libogc and the coorperation
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 9d88dd73ef..a17bdc50cf 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -25,7 +25,6 @@
#include "common/md5.h"
-#include "common/events.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/config-manager.h"
@@ -61,9 +60,6 @@ void AgiEngine::processEvents() {
while (_eventMan->pollEvent(event)) {
switch (event.type) {
- case Common::EVENT_QUIT:
- _game.quitProgNow = true;
- break;
case Common::EVENT_PREDICTIVE_DIALOG:
if (_predictiveDialogRunning)
break;
@@ -738,6 +734,8 @@ void AgiEngine::initialize() {
_gfx->initVideo();
_sound->initSound();
+ _lastSaveTime = 0;
+
_timer->installTimerProc(agiTimerFunctionLow, 10 * 1000, NULL);
_game.ver = -1; /* Don't display the conf file warning */
@@ -812,4 +810,14 @@ int AgiEngine::go() {
return 0;
}
+void AgiEngine::syncSoundSettings() {
+ int soundVolumeMusic = ConfMan.getInt("music_volume");
+ int soundVolumeSFX = ConfMan.getInt("music_volume");
+ int soundVolumeSpeech = ConfMan.getInt("music_volume");
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
+}
+
} // End of namespace Agi
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 9240d562af..ff2b05ace1 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -530,7 +530,6 @@ struct AgiGame {
/* internal flags */
int playerControl; /**< player is in control */
- int quitProgNow; /**< quit now */
int statusLine; /**< status line on/off */
int clockEnabled; /**< clock is on/off */
int exitAllLogics; /**< break cycle after new.room */
@@ -747,6 +746,8 @@ protected:
int go();
void initialize();
+ uint32 _lastSaveTime;
+
public:
AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc);
virtual ~AgiEngine();
@@ -754,6 +755,8 @@ public:
return _gameId;
}
+ virtual void syncSoundSettings();
+
private:
int _keyQueue[KEY_QUEUE_SIZE];
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index e0babdf926..3d29f45ea5 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -24,7 +24,6 @@
*/
-
#include "agi/agi.h"
#include "agi/sprite.h"
#include "agi/graphics.h"
@@ -116,7 +115,7 @@ void AgiEngine::interpretCycle() {
oldSound = getflag(fSoundOn);
_game.exitAllLogics = false;
- while (runLogic(0) == 0 && !_game.quitProgNow) {
+ while (runLogic(0) == 0 && !quit()) {
_game.vars[vWordNotFound] = 0;
_game.vars[vBorderTouchObj] = 0;
_game.vars[vBorderCode] = 0;
@@ -314,7 +313,6 @@ int AgiEngine::playGame() {
setvar(vTimeDelay, 2); /* "normal" speed */
_game.gfxMode = true;
- _game.quitProgNow = false;
_game.clockEnabled = true;
_game.lineUserInput = 22;
@@ -354,10 +352,16 @@ int AgiEngine::playGame() {
_game.vars[vKey] = 0;
}
- if (_game.quitProgNow == 0xff)
- ec = errRestartGame;
+ // FIXME: This has been broken with the merge of the RTL GSoC project. quit() returns a boolean, and we're trying to
+ // check it against 0xff, which is never going to be true
+ //if (quit() == 0xff)
+ // ec = errRestartGame;
+
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ saveGame(getSavegameFilename(0), "Autosave");
+ }
- } while (_game.quitProgNow == 0);
+ } while (quit() == 0);
_sound->stopSound();
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index cd6942f9c0..2b2d7e080b 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -2122,11 +2122,23 @@ public:
return "Sierra AGI Engine (C) Sierra On-Line Software";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
-
- const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+
+ const Common::ADGameDescription *fallbackDetect(const Common::FSList *fslist) const;
};
+bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
+
bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Agi::AGIGameDescription *gd = (const Agi::AGIGameDescription *)desc;
bool res = true;
@@ -2147,7 +2159,48 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common:
return res;
}
-const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fslist) const {
+SaveStateList AgiMetaEngine::listSaves(const char *target) const {
+ const uint32 AGIflag = MKID_BE('AGI:');
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[31];
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ uint32 type = in->readUint32BE();
+ if (type == AGIflag)
+ in->read(saveDesc, 31);
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void AgiMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".%03d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
+const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSList *fslist) const {
typedef Common::HashMap<Common::String, int32> IntMap;
IntMap allFiles;
bool matchedUsingFilenames = false;
@@ -2156,7 +2209,7 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl
WagFileParser wagFileParser;
Common::String wagFilePath;
Common::String description;
- FSList fslistCurrentDir; // Only used if fslist == NULL
+ Common::FSList fslistCurrentDir; // Only used if fslist == NULL
// // Set the defaults for gameid and extra
_gameid = "agi-fanmade";
@@ -2169,8 +2222,8 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl
if (path.empty())
path = ".";
- FilesystemNode fsCurrentDir(path);
- fsCurrentDir.getChildren(fslistCurrentDir, FilesystemNode::kListFilesOnly);
+ Common::FilesystemNode fsCurrentDir(path);
+ fsCurrentDir.getChildren(fslistCurrentDir, Common::FilesystemNode::kListFilesOnly);
fslist = &fslistCurrentDir;
}
@@ -2185,7 +2238,7 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const FSList *fsl
g_fallbackDesc.version = 0x2917;
// First grab all filenames and at the same time count the number of *.wag files
- for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
+ for (Common::FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
if (file->isDirectory()) continue;
Common::String filename = file->getName();
filename.toLowercase();
diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp
index dcf7d83809..656ae232ec 100644
--- a/engines/agi/loader_v3.cpp
+++ b/engines/agi/loader_v3.cpp
@@ -47,15 +47,15 @@ int AgiLoader_v3::detectGame() {
int ec = errUnk;
bool found = false;
- FSList fslist;
- FilesystemNode dir(ConfMan.get("path"));
+ Common::FSList fslist;
+ Common::FilesystemNode dir(ConfMan.get("path"));
- if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) {
+ if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) {
warning("AgiEngine: invalid game path '%s'", dir.getPath().c_str());
return errInvalidAGIFile;
}
- for (FSList::const_iterator file = fslist.begin();
+ for (Common::FSList::const_iterator file = fslist.begin();
file != fslist.end() && !found; ++file) {
Common::String f = file->getName();
f.toLowercase();
@@ -230,8 +230,8 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
debugC(3, kDebugLevelResources, "offset = %d", agid->offset);
debugC(3, kDebugLevelResources, "x = %x %x", x[0], x[1]);
error("ACK! BAD RESOURCE");
-
- g_system->quit();
+
+ _vm->quitGame();
}
agid->len = READ_LE_UINT16((uint8 *) x + 3); /* uncompressed size */
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 7ecedfbc8c..758bff0cb6 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1213,11 +1213,11 @@ cmd(quit) {
g_sound->stopSound();
if (p0) {
- game.quitProgNow = true;
+ g_agi->quitGame();
} else {
if (g_agi->selectionBox
(" Quit the game, or continue? \n\n\n", buttons) == 0) {
- game.quitProgNow = true;
+ g_agi->quitGame();
}
}
}
@@ -1231,7 +1231,7 @@ cmd(restart_game) {
g_agi->selectionBox(" Restart game, or continue? \n\n\n", buttons);
if (sel == 0) {
- game.quitProgNow = 0xff;
+ g_agi->quitGame();
g_agi->setflag(fRestartGame, true);
g_agi->_menu->enableAll();
}
@@ -1739,7 +1739,7 @@ int AgiEngine::runLogic(int n) {
curLogic->cIP = curLogic->sIP;
timerHack = 0;
- while (ip < _game.logics[n].size && !_game.quitProgNow) {
+ while (ip < _game.logics[n].size && !quit()) {
if (_debug.enabled) {
if (_debug.steps > 0) {
if (_debug.logic0 || n) {
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 7ba3e625bf..393057ed9c 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -24,7 +24,6 @@
*/
-
#include "agi/agi.h"
#include "agi/keyboard.h"
#include "agi/opcodes.h"
@@ -232,7 +231,7 @@ int AgiEngine::testIfCode(int lognum) {
uint8 p[16] = { 0 };
bool end_test = false;
- while (retval && !game.quitProgNow && !end_test) {
+ while (retval && !quit() && !end_test) {
if (_debug.enabled && (_debug.logic0 || lognum))
debugConsole(lognum, lTEST_MODE, NULL);
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index f2301e012a..666d1b1b11 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/events.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/config-manager.h"
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h
index 500f98546b..d95035a073 100644
--- a/engines/agi/preagi.h
+++ b/engines/agi/preagi.h
@@ -73,7 +73,7 @@ public:
// Keyboard
int getSelection(SelectionTypes type);
- int rnd(int hi) { return (_rnd->getRandomNumber(hi) + 1); }
+ int rnd(int hi) { return (_rnd->getRandomNumber(hi - 1) + 1); }
// Text
void drawStr(int row, int col, int attr, const char *buffer);
diff --git a/engines/agi/preagi_common.cpp b/engines/agi/preagi_common.cpp
index 5d99dfa7f9..3cd04351f7 100644
--- a/engines/agi/preagi_common.cpp
+++ b/engines/agi/preagi_common.cpp
@@ -23,8 +23,6 @@
*
*/
-#include "common/events.h"
-
#include "agi/preagi.h"
#include "agi/font.h"
#include "agi/graphics.h"
@@ -122,11 +120,12 @@ void PreAgiEngine::printStrXOR(char *szMsg) {
int PreAgiEngine::getSelection(SelectionTypes type) {
Common::Event event;
- for (;;) {
+ while (!quit()) {
while (_eventMan->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _system->quit();
+ return 0;
case Common::EVENT_RBUTTONUP:
return 0;
case Common::EVENT_LBUTTONUP:
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index 08f8969ca3..f643ab9cfc 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/events.h"
#include "common/savefile.h"
#include "common/stream.h"
@@ -343,11 +342,12 @@ bool Mickey::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) {
drawMenu(menu, *sel0, *sel1);
- for (;;) {
+ for(;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- exit(0);
+ return 0;
case Common::EVENT_MOUSEMOVE:
if (iRow < 2) {
x = event.mouse.x / 8;
@@ -640,8 +640,8 @@ void Mickey::playSound(ENUM_MSA_SOUND iSound) {
if (iSound == IDI_MSA_SND_THEME) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->_system->quit();
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_KEYDOWN:
@@ -932,10 +932,17 @@ bool Mickey::loadGame() {
if (_vm->getSelection(kSelAnyKey) == 0)
return false;
} else {
- if (infile->readUint32BE() != MKID_BE('MICK'))
- error("Mickey::loadGame wrong save game format");
+ if (infile->readUint32BE() != MKID_BE('MICK')) {
+ warning("Mickey::loadGame wrong save game format");
+ return false;
+ }
saveVersion = infile->readByte();
+ if (saveVersion < 2) {
+ warning("The planet data in this save game is corrupted. Load aborted");
+ return false;
+ }
+
if (saveVersion != MSA_SAVEGAME_VERSION)
warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, MSA_SAVEGAME_VERSION);
@@ -953,7 +960,7 @@ bool Mickey::loadGame() {
_game.iPlanetXtal[i] = infile->readByte();
for(i = 0; i < IDI_MSA_MAX_PLANET; i++)
- _game.iClue[i] = infile->readByte();
+ _game.iClue[i] = infile->readUint16LE();
infile->read(_game.szAddr, IDI_MSA_MAX_BUTTON + 1);
@@ -1058,7 +1065,7 @@ void Mickey::saveGame() {
outfile->writeByte(_game.iPlanetXtal[i]);
for(i = 0; i < IDI_MSA_MAX_PLANET; i++)
- outfile->writeByte(_game.iClue[i]);
+ outfile->writeUint16LE(_game.iClue[i]);
outfile->write(_game.szAddr, IDI_MSA_MAX_BUTTON + 1);
@@ -1214,7 +1221,7 @@ void Mickey::gameOver() {
}
waitAnyKey();
- exit(0);
+ _vm->quitGame();
}
void Mickey::flipSwitch() {
@@ -2053,8 +2060,8 @@ void Mickey::waitAnyKey(bool anim) {
for (;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->_system->quit();
case Common::EVENT_KEYDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
@@ -2153,7 +2160,7 @@ void Mickey::run() {
intro();
// Game loop
- for (;;) {
+ while (!_vm->quit()) {
drawRoom();
if (_game.fIntro) {
diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h
index 8d982dc401..f29d2fbccd 100644
--- a/engines/agi/preagi_mickey.h
+++ b/engines/agi/preagi_mickey.h
@@ -30,7 +30,7 @@
namespace Agi {
-#define MSA_SAVEGAME_VERSION 1
+#define MSA_SAVEGAME_VERSION 2
// strings
#define IDS_MSA_PATH_DAT "dat/%s"
@@ -637,7 +637,7 @@ const int IDO_MSA_NEXT_PIECE[IDI_MSA_MAX_PLANET][5] = {
{0x5B78, 0x5BB6, 0x5C29, 0x5C76, 0x5CE1}, // pluto
{0x526B, 0x52DA, 0x5340, 0x53A1, 0x540C}, // jupiter
{0x50F6, 0x512C, 0x5170, 0x51D5, 0x5228}, // mars
- {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus
+ {0x56AA, 0x571C, 0x579E, 0x5807, 0x5875} // uranus
};
// message offsets
@@ -697,7 +697,7 @@ struct MSA_GAME {
uint8 nXtals;
uint8 iPlanetXtal[IDI_MSA_MAX_DAT];
- uint8 iClue[IDI_MSA_MAX_PLANET];
+ uint16 iClue[IDI_MSA_MAX_PLANET];
char szAddr[IDI_MSA_MAX_BUTTON + 1];
// Flags
diff --git a/engines/agi/preagi_troll.cpp b/engines/agi/preagi_troll.cpp
index 7502c63c6c..beff721fda 100644
--- a/engines/agi/preagi_troll.cpp
+++ b/engines/agi/preagi_troll.cpp
@@ -30,8 +30,6 @@
#include "graphics/cursorman.h"
-#include "common/events.h"
-
namespace Agi {
Troll::Troll(PreAgiEngine* vm) : _vm(vm) {
@@ -58,11 +56,12 @@ bool Troll::getMenuSel(const char *szMenu, int *iSel, int nSel) {
drawMenu(szMenu, *iSel);
- for (;;) {
+ while (!_vm->quit()) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->_system->quit();
+ return 0;
case Common::EVENT_MOUSEMOVE:
y = event.mouse.y / 8;
@@ -205,8 +204,8 @@ void Troll::waitAnyKeyIntro() {
for (;;) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->_system->quit();
case Common::EVENT_LBUTTONUP:
case Common::EVENT_KEYDOWN:
return;
@@ -269,7 +268,7 @@ void Troll::tutorial() {
int iSel = 0;
//char szTreasure[16] = {0};
- for (;;) {
+ while (!_vm->quit()) {
_vm->clearScreen(0xFF);
_vm->printStr(IDS_TRO_TUTORIAL_0);
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index 87d13bff3d..de8839b7bc 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -29,7 +29,6 @@
#include "graphics/cursorman.h"
-#include "common/events.h"
#include "common/savefile.h"
#include "common/stream.h"
@@ -797,12 +796,12 @@ void Winnie::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
// Show the mouse cursor for the menu
CursorMan.showMouse(true);
- for (;;) {
+ while (!_vm->quit()) {
while (_vm->_system->getEventManager()->pollEvent(event)) {
switch(event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->_system->quit();
- break;
+ return;
case Common::EVENT_MOUSEMOVE:
x = event.mouse.x / 8;
y = event.mouse.y / 8;
@@ -1014,7 +1013,7 @@ phase2:
if (parser(hdr.ofsDesc[iBlock] - _roomOffset, iBlock, roomdata) == IDI_WTP_PAR_BACK)
goto phase1;
}
- for (;;) {
+ while (!_vm->quit()) {
for (iBlock = 0; iBlock < IDI_WTP_MAX_BLOCK; iBlock++) {
switch(parser(hdr.ofsBlock[iBlock] - _roomOffset, iBlock, roomdata)) {
case IDI_WTP_PAR_GOTO:
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index db7bba13e4..0b308bb37b 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -91,7 +91,7 @@ int AgiEngine::saveGame(const char *fileName, const char *description) {
out->writeSint16BE((int16)_game.lognum);
out->writeSint16BE((int16)_game.playerControl);
- out->writeSint16BE((int16)_game.quitProgNow);
+ out->writeSint16BE((int16)quit());
out->writeSint16BE((int16)_game.statusLine);
out->writeSint16BE((int16)_game.clockEnabled);
out->writeSint16BE((int16)_game.exitAllLogics);
@@ -214,6 +214,9 @@ int AgiEngine::saveGame(const char *fileName, const char *description) {
delete out;
debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName);
+
+ _lastSaveTime = _system->getMillis();
+
return result;
}
@@ -281,7 +284,8 @@ int AgiEngine::loadGame(const char *fileName, bool checkId) {
_game.lognum = in->readSint16BE();
_game.playerControl = in->readSint16BE();
- _game.quitProgNow = in->readSint16BE();
+ if (in->readSint16BE())
+ quitGame();
_game.statusLine = in->readSint16BE();
_game.clockEnabled = in->readSint16BE();
_game.exitAllLogics = in->readSint16BE();
@@ -698,13 +702,18 @@ int AgiEngine::saveGameDialog() {
sprintf(fileName, "%s", getSavegameFilename(slot));
- drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
- printText("Select a slot in which you wish to\nsave the game:",
- 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
- slot = selectSlot();
- if (slot < 0)
- return errOK;
+ do {
+ drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp);
+ printText("Select a slot in which you wish to\nsave the game:",
+ 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOUR);
+ slot = selectSlot();
+ if (slot == 0)
+ messageBox("That slot is for Autosave only.");
+ else if (slot < 0)
+ return errOK;
+ }
+ while (slot == 0);
drawWindow(hp, vp + 5 * CHAR_LINES, GFX_WIDTH - hp,
GFX_HEIGHT - vp - 9 * CHAR_LINES);
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index 77f79272f8..3b28e75c56 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -435,13 +435,10 @@ void IIgsMidiChannel::stopSounds() {
_gsChannels.clear();
}
-static int16 *buffer;
-
int SoundMgr::initSound() {
int r = -1;
- buffer = _sndBuffer = (int16 *)calloc(2, BUFFER_SIZE);
-
+ memset(_sndBuffer, 0, BUFFER_SIZE << 1);
_env = false;
switch (_vm->_soundemu) {
@@ -478,7 +475,6 @@ int SoundMgr::initSound() {
void SoundMgr::deinitSound() {
debugC(3, kDebugLevelSound, "()");
_mixer->stopHandle(_soundHandle);
- free(_sndBuffer);
}
void SoundMgr::stopNote(int i) {
@@ -1017,7 +1013,7 @@ bool IIgsSoundMgr::loadInstrumentHeaders(const Common::String &exePath, const II
// Open the executable file and check that it has correct size
file.open(exePath);
- if (file.size() != exeInfo.exeSize) {
+ if (file.size() != (int32)exeInfo.exeSize) {
debugC(3, kDebugLevelSound, "Apple IIGS executable (%s) has wrong size (Is %d, should be %d)",
exePath.c_str(), file.size(), exeInfo.exeSize);
}
@@ -1027,7 +1023,7 @@ bool IIgsSoundMgr::loadInstrumentHeaders(const Common::String &exePath, const II
file.close();
// Check that we got enough data to be able to parse the instruments
- if (data && data->size() >= (exeInfo.instSetStart + exeInfo.instSet.byteCount)) {
+ if (data && data->size() >= (int32)(exeInfo.instSetStart + exeInfo.instSet.byteCount)) {
// Check instrument set's length (The info's saved in the executable)
data->seek(exeInfo.instSetStart - 4);
uint16 instSetByteCount = data->readUint16LE();
@@ -1111,14 +1107,14 @@ bool IIgsSoundMgr::loadWaveFile(const Common::String &wavePath, const IIgsExeInf
}
/**
- * A function object (i.e. a functor) for testing if a FilesystemNode
+ * A function object (i.e. a functor) for testing if a Common::FilesystemNode
* object's name is equal (Ignoring case) to a string or to at least
* one of the strings in a list of strings. Can be used e.g. with find_if().
*/
-struct fsnodeNameEqualsIgnoreCase : public Common::UnaryFunction<const FilesystemNode&, bool> {
+struct fsnodeNameEqualsIgnoreCase : public Common::UnaryFunction<const Common::FilesystemNode&, bool> {
fsnodeNameEqualsIgnoreCase(const Common::StringList &str) : _str(str) {}
fsnodeNameEqualsIgnoreCase(const Common::String str) { _str.push_back(str); }
- bool operator()(const FilesystemNode &param) const {
+ bool operator()(const Common::FilesystemNode &param) const {
for (Common::StringList::const_iterator iter = _str.begin(); iter != _str.end(); iter++)
if (param.getName().equalsIgnoreCase(*iter))
return true;
@@ -1143,9 +1139,9 @@ bool SoundMgr::loadInstruments() {
}
// List files in the game path
- FSList fslist;
- FilesystemNode dir(ConfMan.get("path"));
- if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) {
+ Common::FSList fslist;
+ Common::FilesystemNode dir(ConfMan.get("path"));
+ if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) {
warning("Invalid game path (\"%s\"), not loading Apple IIGS instruments", dir.getPath().c_str());
return false;
}
@@ -1161,7 +1157,7 @@ bool SoundMgr::loadInstruments() {
waveNames.push_back("SIERRAST");
// Search for the executable file and the wave file (i.e. check if any of the filenames match)
- FSList::const_iterator exeFsnode, waveFsnode;
+ Common::FSList::const_iterator exeFsnode, waveFsnode;
exeFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(exeNames));
waveFsnode = Common::find_if(fslist.begin(), fslist.end(), fsnodeNameEqualsIgnoreCase(waveNames));
@@ -1185,7 +1181,7 @@ bool SoundMgr::loadInstruments() {
return _gsSound.loadWaveFile(waveFsnode->getPath(), *exeInfo) && _gsSound.loadInstrumentHeaders(exeFsnode->getPath(), *exeInfo);
}
-static void fillAudio(void *udata, int16 *stream, uint len) {
+void SoundMgr::fillAudio(void *udata, int16 *stream, uint len) {
SoundMgr *soundMgr = (SoundMgr *)udata;
uint32 p = 0;
static uint32 n = 0, s = 0;
@@ -1193,32 +1189,34 @@ static void fillAudio(void *udata, int16 *stream, uint len) {
len <<= 2;
debugC(5, kDebugLevelSound, "(%p, %p, %d)", (void *)udata, (void *)stream, len);
- memcpy(stream, (uint8 *)buffer + s, p = n);
+ memcpy(stream, (uint8 *)_sndBuffer + s, p = n);
for (n = 0, len -= p; n < len; p += n, len -= n) {
soundMgr->playSound();
n = soundMgr->mixSound() << 1;
if (len < n) {
- memcpy((uint8 *)stream + p, buffer, len);
+ memcpy((uint8 *)stream + p, _sndBuffer, len);
s = len;
n -= s;
return;
} else {
- memcpy((uint8 *)stream + p, buffer, n);
+ memcpy((uint8 *)stream + p, _sndBuffer, n);
}
}
soundMgr->playSound();
n = soundMgr->mixSound() << 1;
- memcpy((uint8 *)stream + p, buffer, s = len);
+ memcpy((uint8 *)stream + p, _sndBuffer, s = len);
n -= s;
}
-SoundMgr::SoundMgr(AgiBase *agi, Audio::Mixer *pMixer) {
+SoundMgr::SoundMgr(AgiBase *agi, Audio::Mixer *pMixer) : _chn() {
_vm = agi;
_mixer = pMixer;
_sampleRate = pMixer->getOutputRate();
_endflag = -1;
_playingSound = -1;
- _sndBuffer = 0;
+ _env = false;
+ _playing = false;
+ _sndBuffer = (int16 *)calloc(2, BUFFER_SIZE);
_waveform = 0;
}
@@ -1231,6 +1229,7 @@ void SoundMgr::setVolume(uint8 volume) {
}
SoundMgr::~SoundMgr() {
+ free(_sndBuffer);
}
} // End of namespace Agi
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index f1c2782421..a1f079891f 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -472,6 +472,7 @@ private:
const int16 *_waveform;
void premixerCall(int16 *buf, uint len);
+ void fillAudio(void *udata, int16 *stream, uint len);
public:
void unloadSound(int);
diff --git a/engines/agi/wagparser.h b/engines/agi/wagparser.h
index 2f4003315f..827720ac85 100644
--- a/engines/agi/wagparser.h
+++ b/engines/agi/wagparser.h
@@ -201,7 +201,9 @@ protected:
class WagFileParser {
// Constants, type definitions, enumerations etc.
public:
- static const uint WINAGI_VERSION_LENGTH = 16; ///< WinAGI's version string's length (Always 16)
+ enum {
+ WINAGI_VERSION_LENGTH = 16 ///< WinAGI's version string's length (Always 16)
+ };
typedef Common::Array<WagProperty> PropertyList; ///< A type definition for an array of *.wag file properties
public:
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp
index a9fd204d73..97d84e036c 100644
--- a/engines/agos/agos.cpp
+++ b/engines/agos/agos.cpp
@@ -97,8 +97,6 @@ AGOSEngine::AGOSEngine(OSystem *syst)
_vc_get_out_of_code = 0;
_gameOffsetsPtr = 0;
- _quit = false;
-
_debugger = 0;
_gameFile = 0;
@@ -508,24 +506,24 @@ AGOSEngine::AGOSEngine(OSystem *syst)
// Add default file directories for Acorn version of
// Simon the Sorcerer 1
- File::addDefaultDirectory(_gameDataPath + "execute");
- File::addDefaultDirectory(_gameDataPath + "EXECUTE");
+ File::addDefaultDirectory(_gameDataDir.getChild("execute"));
+ File::addDefaultDirectory(_gameDataDir.getChild("EXECUTE"));
// Add default file directories for Amiga/Macintosh
// verisons of Simon the Sorcerer 2
- File::addDefaultDirectory(_gameDataPath + "voices");
- File::addDefaultDirectory(_gameDataPath + "VOICES");
+ File::addDefaultDirectory(_gameDataDir.getChild("voices"));
+ File::addDefaultDirectory(_gameDataDir.getChild("VOICES"));
// Add default file directories for Amiga & Macintosh
// versions of The Feeble Files
- File::addDefaultDirectory(_gameDataPath + "gfx");
- File::addDefaultDirectory(_gameDataPath + "GFX");
- File::addDefaultDirectory(_gameDataPath + "movies");
- File::addDefaultDirectory(_gameDataPath + "MOVIES");
- File::addDefaultDirectory(_gameDataPath + "sfx");
- File::addDefaultDirectory(_gameDataPath + "SFX");
- File::addDefaultDirectory(_gameDataPath + "speech");
- File::addDefaultDirectory(_gameDataPath + "SPEECH");
+ File::addDefaultDirectory(_gameDataDir.getChild("gfx"));
+ File::addDefaultDirectory(_gameDataDir.getChild("GFX"));
+ File::addDefaultDirectory(_gameDataDir.getChild("movies"));
+ File::addDefaultDirectory(_gameDataDir.getChild("MOVIES"));
+ File::addDefaultDirectory(_gameDataDir.getChild("sfx"));
+ File::addDefaultDirectory(_gameDataDir.getChild("SFX"));
+ File::addDefaultDirectory(_gameDataDir.getChild("speech"));
+ File::addDefaultDirectory(_gameDataDir.getChild("SPEECH"));
syst->getEventManager()->registerRandomSource(_rnd, "agos");
}
@@ -550,6 +548,7 @@ int AGOSEngine::init() {
// Setup mixer
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
if ((getGameType() == GType_SIMON2 && getPlatform() == Common::kPlatformWindows) ||
(getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) ||
@@ -574,7 +573,7 @@ int AGOSEngine::init() {
if (ret)
warning("MIDI Player init failed: \"%s\"", _midi.getErrorName (ret));
- _midi.setVolume(ConfMan.getInt("music_volume"));
+ _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume"));
_midiEnabled = true;
@@ -952,7 +951,7 @@ void AGOSEngine::pauseEngineIntern(bool pauseIt) {
void AGOSEngine::pause() {
pauseEngine(true);
- while (_pause && !_quit) {
+ while (_pause && !quit()) {
delay(1);
if (_keyPressed.keycode == Common::KEYCODE_p)
pauseEngine(false);
@@ -989,7 +988,7 @@ int AGOSEngine::go() {
(getFeatures() & GF_DEMO)) {
int i;
- while (!_quit) {
+ while (!quit()) {
for (i = 0; i < 4; i++) {
setWindowImage(3, 9902 + i);
debug(0, "Displaying image %d", 9902 + i);
@@ -1018,7 +1017,7 @@ int AGOSEngine::go() {
runSubroutine101();
permitInput();
- while (!_quit) {
+ while (!quit()) {
waitForInput();
handleVerbClicked(_verbHitArea);
delay(100);
@@ -1084,4 +1083,12 @@ uint32 AGOSEngine::getTime() const {
return (uint32)time(NULL);
}
+
+void AGOSEngine::syncSoundSettings() {
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+ _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume"));
+}
+
} // End of namespace AGOS
diff --git a/engines/agos/agos.h b/engines/agos/agos.h
index 8ad5487b35..49b4478ec7 100644
--- a/engines/agos/agos.h
+++ b/engines/agos/agos.h
@@ -269,7 +269,6 @@ protected:
uint16 _marks;
- bool _quit;
bool _scriptVar2;
bool _runScriptReturn1;
bool _runScriptCondition[40];
@@ -589,6 +588,8 @@ protected:
void loadSoundFile(const char *filename);
+ virtual void syncSoundSettings();
+
int getUserFlag(Item *item, int a);
int getUserFlag1(Item *item, int a);
int getUserItem(Item *item, int n);
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index c92f834a3b..f4abf19645 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -26,7 +26,6 @@
#include "common/endian.h"
-#include "common/events.h"
#include "common/system.h"
#include "graphics/cursorman.h"
@@ -151,7 +150,7 @@ void MoviePlayer::play() {
startSound();
- while (_frameNum < _framesCount)
+ while (_frameNum < _framesCount && !_vm->quit())
handleNextFrame();
closeFile();
@@ -167,7 +166,7 @@ void MoviePlayer::play() {
_vm->_system->setPalette(palette, 0, 256);
}
- _vm->fillBackGroundFromBack();
+ _vm->fillBackGroundFromBack();
_vm->_fastFadeOutFlag = true;
}
@@ -279,9 +278,6 @@ void MoviePlayer::handleNextFrame() {
case Common::EVENT_RBUTTONUP:
_rightButtonDown = false;
break;
- case Common::EVENT_QUIT:
- _vm->_quit = true;
- break;
default:
break;
}
diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp
index 26d8916ab7..12f281d0dc 100644
--- a/engines/agos/detection.cpp
+++ b/engines/agos/detection.cpp
@@ -27,6 +27,7 @@
#include "common/advancedDetector.h"
#include "common/config-manager.h"
+#include "common/savefile.h"
#include "agos/agos.h"
@@ -100,7 +101,7 @@ static const Common::ADParams detectionParams = {
class AgosMetaEngine : public Common::AdvancedMetaEngine {
public:
AgosMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {}
-
+
virtual const char *getName() const {
return "AGOS";
}
@@ -108,10 +109,18 @@ public:
virtual const char *getCopyright() const {
return "AGOS (C) Adventure Soft";
}
-
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
};
+bool AgosMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves);
+}
+
bool AgosMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const AGOS::AGOSGameDescription *gd = (const AGOS::AGOSGameDescription *)desc;
bool res = true;
@@ -149,6 +158,34 @@ bool AgosMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return res;
}
+SaveStateList AgosMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ Common::String saveDesc;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ saveDesc = file->c_str();
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(AGOS)
REGISTER_PLUGIN_DYNAMIC(AGOS, PLUGIN_TYPE_ENGINE, AgosMetaEngine);
#else
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
index 010b331cf8..4db3545594 100644
--- a/engines/agos/event.cpp
+++ b/engines/agos/event.cpp
@@ -142,7 +142,7 @@ bool AGOSEngine::kickoffTimeEvents() {
cur_time = getTime() - _gameStoppedClock;
- while ((te = _firstTimeStruct) != NULL && te->time <= cur_time && !_quit) {
+ while ((te = _firstTimeStruct) != NULL && te->time <= cur_time && !quit()) {
result = true;
_pendingDeleteTimeEvent = te;
invokeTimeEvent(te);
@@ -520,8 +520,8 @@ void AGOSEngine::delay(uint amount) {
setBitFlag(92, false);
_rightButtonDown++;
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _quit = true;
return;
default:
break;
@@ -544,7 +544,7 @@ void AGOSEngine::delay(uint amount) {
_system->delayMillis(this_delay);
cur = _system->getMillis();
- } while (cur < start + amount && !_quit);
+ } while (cur < start + amount && !quit());
}
void AGOSEngine::timer_callback() {
diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp
index 9a3962ea21..25a4b919f4 100644
--- a/engines/agos/gfx.cpp
+++ b/engines/agos/gfx.cpp
@@ -1286,7 +1286,7 @@ void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vga_res) {
if (getGameType() == GType_WW && (mode == 6 || mode == 8 || mode == 9)) {
setWindowImage(mode, vga_res);
} else {
- while (_copyScnFlag && !_quit)
+ while (_copyScnFlag && !quit())
delay(1);
setWindowImage(mode, vga_res);
diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp
index d36549f187..4327c2878d 100644
--- a/engines/agos/input.cpp
+++ b/engines/agos/input.cpp
@@ -123,7 +123,7 @@ void AGOSEngine::setup_cond_c_helper() {
clearName();
_lastNameOn = last;
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = 0;
_leftButtonDown = 0;
@@ -145,7 +145,7 @@ void AGOSEngine::setup_cond_c_helper() {
}
delay(100);
- } while (_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0);
+ } while ((_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0) && !quit());
if (_lastHitArea == NULL) {
} else if (_lastHitArea->id == 0x7FFB) {
@@ -189,12 +189,12 @@ void AGOSEngine::waitForInput() {
resetVerbs();
}
- while (!_quit) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
_dragAccept = 1;
- while (!_quit) {
+ while (!quit()) {
if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) &&
_keyPressed.keycode == Common::KEYCODE_F10)
displayBoxStars();
@@ -563,16 +563,18 @@ bool AGOSEngine::processSpecialKeys() {
case Common::KEYCODE_PLUS:
case Common::KEYCODE_KP_PLUS:
if (_midiEnabled) {
- _midi.setVolume(_midi.getVolume() + 16);
+ _midi.setVolume(_midi.getMusicVolume() + 16, _midi.getSFXVolume() + 16);
}
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16);
+ ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16);
+ syncSoundSettings();
break;
case Common::KEYCODE_MINUS:
case Common::KEYCODE_KP_MINUS:
if (_midiEnabled) {
- _midi.setVolume(_midi.getVolume() - 16);
+ _midi.setVolume(_midi.getMusicVolume() - 16, _midi.getSFXVolume() - 16);
}
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16);
+ ConfMan.setInt("music_volume", _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16);
+ syncSoundSettings();
break;
case Common::KEYCODE_m:
_musicPaused ^= 1;
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
index 3114b24549..fd0e4eaa9d 100644
--- a/engines/agos/midi.cpp
+++ b/engines/agos/midi.cpp
@@ -49,7 +49,9 @@ MidiPlayer::MidiPlayer() {
_enable_sfx = true;
_current = 0;
- _masterVolume = 255;
+ _musicVolume = 255;
+ _sfxVolume = 255;
+
resetVolumeTable();
_paused = false;
@@ -104,10 +106,13 @@ void MidiPlayer::send(uint32 b) {
byte channel = (byte)(b & 0x0F);
if ((b & 0xFFF0) == 0x07B0) {
- // Adjust volume changes by master volume.
+ // Adjust volume changes by master music and master sfx volume.
byte volume = (byte)((b >> 16) & 0x7F);
_current->volume[channel] = volume;
- volume = volume * _masterVolume / 255;
+ if (_current == &_sfx)
+ volume = volume * _sfxVolume / 255;
+ else if (_current == &_music)
+ volume = volume * _musicVolume / 255;
b = (b & 0xFF00FFFF) | (volume << 16);
} else if ((b & 0xF0) == 0xC0 && _map_mt32_to_gm) {
b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
@@ -133,8 +138,12 @@ void MidiPlayer::send(uint32 b) {
if (!_current->channel[channel])
_current->channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
if (_current->channel[channel]) {
- if (channel == 9)
- _current->channel[9]->volume(_current->volume[9] * _masterVolume / 255);
+ if (channel == 9) {
+ if (_current == &_sfx)
+ _current->channel[9]->volume(_current->volume[9] * _sfxVolume / 255);
+ else if (_current == &_music)
+ _current->channel[9]->volume(_current->volume[9] * _musicVolume / 255);
+ }
_current->channel[channel]->send(b);
if ((b & 0xFFF0) == 0x79B0) {
// We have received a "Reset All Controllers" message
@@ -143,7 +152,10 @@ void MidiPlayer::send(uint32 b) {
// consistent behaviour, explicitly set the volume to
// what we think it should be.
- _current->channel[channel]->volume(_current->volume[channel] * _masterVolume / 255);
+ if (_current == &_sfx)
+ _current->channel[channel]->volume(_current->volume[channel] * _sfxVolume / 255);
+ else if (_current == &_music)
+ _current->channel[channel]->volume(_current->volume[channel] * _musicVolume / 255);
}
}
}
@@ -255,30 +267,36 @@ void MidiPlayer::pause(bool b) {
Common::StackLock lock(_mutex);
for (int i = 0; i < 16; ++i) {
if (_music.channel[i])
- _music.channel[i]->volume(_paused ? 0 : (_music.volume[i] * _masterVolume / 255));
+ _music.channel[i]->volume(_paused ? 0 : (_music.volume[i] * _musicVolume / 255));
if (_sfx.channel[i])
- _sfx.channel[i]->volume(_paused ? 0 : (_sfx.volume[i] * _masterVolume / 255));
+ _sfx.channel[i]->volume(_paused ? 0 : (_sfx.volume[i] * _sfxVolume / 255));
}
}
-void MidiPlayer::setVolume(int volume) {
- if (volume < 0)
- volume = 0;
- else if (volume > 255)
- volume = 255;
-
- if (_masterVolume == volume)
+void MidiPlayer::setVolume(int musicVol, int sfxVol) {
+ if (musicVol < 0)
+ musicVol = 0;
+ else if (musicVol > 255)
+ musicVol = 255;
+ if (sfxVol < 0)
+ sfxVol = 0;
+ else if (sfxVol > 255)
+ sfxVol = 255;
+
+ if (_musicVolume == musicVol && _sfxVolume == sfxVol)
return;
- _masterVolume = volume;
+
+ _musicVolume = musicVol;
+ _sfxVolume = sfxVol;
// Now tell all the channels this.
Common::StackLock lock(_mutex);
if (_driver && !_paused) {
for (int i = 0; i < 16; ++i) {
if (_music.channel[i])
- _music.channel[i]->volume(_music.volume[i] * _masterVolume / 255);
+ _music.channel[i]->volume(_music.volume[i] * _musicVolume / 255);
if (_sfx.channel[i])
- _sfx.channel[i]->volume(_sfx.volume[i] * _masterVolume / 255);
+ _sfx.channel[i]->volume(_sfx.volume[i] * _sfxVolume / 255);
}
}
}
@@ -354,7 +372,7 @@ void MidiPlayer::resetVolumeTable() {
for (i = 0; i < 16; ++i) {
_music.volume[i] = _sfx.volume[i] = 127;
if (_driver)
- _driver->send(((_masterVolume >> 1) << 16) | 0x7B0 | i);
+ _driver->send(((_musicVolume >> 1) << 16) | 0x7B0 | i);
}
}
@@ -538,7 +556,11 @@ void MidiPlayer::loadXMIDI(Common::File *in, bool sfx) {
error("Expected 'FORM' tag but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]);
}
- MidiParser *parser = MidiParser::createParser_XMIDI();
+ // In the DOS version of Simon the Sorcerer 2, the music contains lots
+ // of XMIDI callback controller events. As far as we know, they aren't
+ // actually used, so we disable the callback handler explicitly.
+
+ MidiParser *parser = MidiParser::createParser_XMIDI(NULL);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
if (!parser->loadMusic(p->data, size))
diff --git a/engines/agos/midi.h b/engines/agos/midi.h
index 2994c49bb6..c004230e5b 100644
--- a/engines/agos/midi.h
+++ b/engines/agos/midi.h
@@ -68,6 +68,8 @@ protected:
// These are maintained for both music and SFX
byte _masterVolume; // 0-255
+ byte _musicVolume;
+ byte _sfxVolume;
bool _paused;
// These are only used for music.
@@ -103,8 +105,9 @@ public:
void stop();
void pause(bool b);
- int getVolume() { return _masterVolume; }
- void setVolume(int volume);
+ int getMusicVolume() { return _musicVolume; }
+ int getSFXVolume() { return _sfxVolume; }
+ void setVolume(int musicVol, int sfxVol);
void setDriver(MidiDriver *md);
public:
diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp
index a113c8e2ea..c174362e7c 100644
--- a/engines/agos/oracle.cpp
+++ b/engines/agos/oracle.cpp
@@ -459,7 +459,7 @@ void AGOSEngine_Feeble::saveUserGame(int slot) {
}
windowPutChar(window, 0x7f);
- for (;;) {
+ while (!quit()) {
_keyPressed.reset();
delay(1);
diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp
index 4aca390f3b..cd0d8e7ef6 100644
--- a/engines/agos/res.cpp
+++ b/engines/agos/res.cpp
@@ -74,8 +74,7 @@ void AGOSEngine::decompressData(const char *srcName, byte *dst, uint32 offset, u
error("decompressData: Read failed");
unsigned long decompressedSize = dstSize;
- int result = Common::uncompress(dst, &decompressedSize, srcBuffer, srcSize);
- if (result != Common::ZLIB_OK)
+ if (!Common::uncompress(dst, &decompressedSize, srcBuffer, srcSize))
error("decompressData: Zlib uncompress error");
free(srcBuffer);
} else {
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index 4a5c43e706..c1a4e91c95 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -244,7 +244,7 @@ int16 AGOSEngine::matchSaveGame(const char *name, uint16 max) {
void AGOSEngine::userGame(bool load) {
WindowBlock *window = _windowArray[4];
const char *message1;
- int i, numSaveGames;
+ int i = 0, numSaveGames;
char *name;
char buf[8];
@@ -279,11 +279,11 @@ restart:
name = buf;
_saveGameNameLen = 0;
- for (;;) {
+ while (!quit()) {
windowPutChar(window, 128);
_keyPressed.reset();
- for (;;) {
+ while (!quit()) {
delay(10);
if (_keyPressed.ascii && _keyPressed.ascii < 128) {
i = _keyPressed.ascii;
@@ -443,7 +443,7 @@ void AGOSEngine_Elvira2::userGame(bool load) {
name = buf + 192;
- for (;;) {
+ while (!quit()) {
windowPutChar(window, 128);
_saveLoadEdit = true;
@@ -516,7 +516,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
_keyPressed.reset();
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
@@ -526,7 +526,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
return _keyPressed.ascii;
}
delay(10);
- } while (_lastHitArea3 == 0);
+ } while (_lastHitArea3 == 0 && !quit());
ha = _lastHitArea;
if (ha == NULL || ha->id < 200) {
@@ -543,6 +543,8 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
return ha->id - 200;
}
}
+
+ return 225;
}
void AGOSEngine_Simon1::listSaveGames(char *dst) {
@@ -706,7 +708,7 @@ restart:;
_saveGameNameLen++;
}
- for (;;) {
+ while (!quit()) {
windowPutChar(window, 127);
_saveLoadEdit = true;
@@ -785,7 +787,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
_keyPressed.reset();
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
@@ -795,7 +797,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
return _keyPressed.ascii;
}
delay(10);
- } while (_lastHitArea3 == 0);
+ } while (_lastHitArea3 == 0 && !quit());
ha = _lastHitArea;
if (ha == NULL || ha->id < 205) {
@@ -824,6 +826,8 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
return ha->id - 208;
}
}
+
+ return 205;
}
void AGOSEngine::disableFileBoxes() {
@@ -1052,7 +1056,7 @@ bool AGOSEngine::loadGame(const char *filename, bool restartMode) {
writeVariable(i, f->readUint16BE());
}
- if (f->ioFailed()) {
+ if (f->err()) {
error("load failed");
}
@@ -1136,7 +1140,7 @@ bool AGOSEngine::saveGame(uint slot, const char *caption) {
}
f->finalize();
- bool result = !f->ioFailed();
+ bool result = !f->err();
delete f;
_lockWord &= ~0x100;
@@ -1327,7 +1331,7 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) {
_superRoomNumber = f->readUint16BE();
}
- if (f->ioFailed()) {
+ if (f->err()) {
error("load failed");
}
@@ -1499,7 +1503,7 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) {
}
f->finalize();
- bool result = !f->ioFailed();
+ bool result = !f->err();
delete f;
_lockWord &= ~0x100;
diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp
index 6758aec511..39c172be62 100644
--- a/engines/agos/script.cpp
+++ b/engines/agos/script.cpp
@@ -410,7 +410,7 @@ void AGOSEngine::o_msg() {
void AGOSEngine::o_end() {
// 68: exit interpreter
- _quit = true;
+ quitGame();
}
void AGOSEngine::o_done() {
@@ -965,7 +965,7 @@ void AGOSEngine::writeVariable(uint16 variable, uint16 contents) {
int AGOSEngine::runScript() {
bool flag;
- if (_quit)
+ if (quit())
return 1;
do {
@@ -1010,9 +1010,9 @@ int AGOSEngine::runScript() {
error("Invalid opcode '%d' encountered", _opcode);
executeOpcode(_opcode);
- } while (getScriptCondition() != flag && !getScriptReturn() && !_quit);
+ } while (getScriptCondition() != flag && !getScriptReturn() && !quit());
- return getScriptReturn();
+ return (quit()) ? 1 : getScriptReturn();
}
Child *nextSub(Child *sub, int16 key) {
@@ -1066,7 +1066,7 @@ void AGOSEngine::waitForSync(uint a) {
_exitCutscene = false;
_rightButtonDown = false;
- while (_vgaWaitFor != 0 && !_quit) {
+ while (_vgaWaitFor != 0 && !quit()) {
if (_rightButtonDown) {
if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) {
skipSpeech();
diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp
index c7e1d6736e..8705755df6 100644
--- a/engines/agos/script_e1.cpp
+++ b/engines/agos/script_e1.cpp
@@ -24,7 +24,6 @@
*/
-
#include "agos/agos.h"
#include "agos/vga.h"
@@ -565,7 +564,7 @@ void AGOSEngine_Elvira1::oe1_look() {
lobjFunc(l, "You can see "); /* Show objects */
}
if (r && (r->flags & 4) && levelOf(i) < 10000) {
- _quit = true;
+ quitGame();
}
}
@@ -944,7 +943,7 @@ restart:
windowPutChar(window, *message2);
if (confirmYesOrNo(120, 62) == 0x7FFF) {
- _quit = true;
+ quitGame();
} else {
goto restart;
}
@@ -1053,11 +1052,11 @@ uint AGOSEngine::confirmYesOrNo(uint16 x, uint16 y) {
ha->priority = 999;
ha->window = 0;
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!quit()) {
if (_lastHitArea3 != 0)
break;
delay(1);
@@ -1102,11 +1101,11 @@ uint AGOSEngine::continueOrQuit() {
ha->priority = 999;
ha->window = 0;
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!quit()) {
if (_lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp
index da9afc5a7d..05e457579d 100644
--- a/engines/agos/script_e2.cpp
+++ b/engines/agos/script_e2.cpp
@@ -370,11 +370,11 @@ void AGOSEngine_Elvira2::oe2_pauseGame() {
uint32 pauseTime = getTime();
haltAnimation();
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!quit()) {
if (processSpecialKeys() != 0 || _lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp
index 51918b9515..d07f682937 100644
--- a/engines/agos/script_s1.cpp
+++ b/engines/agos/script_s1.cpp
@@ -24,7 +24,6 @@
*/
-
#include "common/system.h"
#include "agos/agos.h"
@@ -339,20 +338,10 @@ void AGOSEngine_Simon1::os1_pauseGame() {
break;
}
- for (;;) {
+ while (!quit()) {
delay(1);
-#ifdef _WIN32_WCE
- if (isSmartphone()) {
- if (_keyPressed.keycode) {
- if (_keyPressed.keycode == Common::KEYCODE_RETURN)
- _quit = true;
- else
- break;
- }
- }
-#endif
if (_keyPressed.keycode == keyYes)
- _quit = true;
+ quitGame();
else if (_keyPressed.keycode == keyNo)
break;
}
diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp
index 5fd83312c3..f0da324fbd 100644
--- a/engines/agos/script_ww.cpp
+++ b/engines/agos/script_ww.cpp
@@ -368,11 +368,11 @@ void AGOSEngine_Waxworks::oww_pauseGame() {
uint32 pauseTime = getTime();
haltAnimation();
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!quit()) {
if (_lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
index c456c92e60..4d60bbdbed 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -56,10 +56,12 @@ protected:
public:
BaseSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false);
BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigEndian = false);
+ virtual ~BaseSound();
+ void close();
+
void playSound(uint sound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0) {
playSound(sound, sound, type, handle, flags, vol);
}
- virtual ~BaseSound();
virtual void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0) = 0;
virtual Audio::AudioStream *makeAudioStream(uint sound) { return NULL; }
};
@@ -184,6 +186,12 @@ BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigE
_freeOffsets = false;
}
+void BaseSound::close() {
+ if (_freeOffsets) {
+ free(_offsets);
+ }
+}
+
BaseSound::~BaseSound() {
if (_freeOffsets)
free(_offsets);
@@ -555,6 +563,9 @@ void Sound::readSfxFile(const char *filename) {
void Sound::loadSfxTable(File *gameFile, uint32 base) {
stopAll();
+
+ if (_effects)
+ _effects->close();
if (_vm->getPlatform() == Common::kPlatformWindows)
_effects = new WavSound(_mixer, gameFile, base);
diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp
index cb71ed7efa..488ebf4edf 100644
--- a/engines/agos/subroutine.cpp
+++ b/engines/agos/subroutine.cpp
@@ -555,7 +555,7 @@ int AGOSEngine::startSubroutine(Subroutine *sub) {
_currentTable = sub;
restart:
- if (_quit)
+ if (quit())
return result;
while ((byte *)sl != (byte *)sub) {
diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp
index 963bd6bd86..9fd128d764 100644
--- a/engines/agos/verb.cpp
+++ b/engines/agos/verb.cpp
@@ -343,6 +343,9 @@ void AGOSEngine::handleVerbClicked(uint verb) {
Subroutine *sub;
int result;
+ if (quit())
+ return;
+
_objectItem = _hitAreaObjectItem;
if (_objectItem == _dummyItem2) {
_objectItem = me();
diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp
index e25bd6b438..87db49e46b 100644
--- a/engines/agos/window.cpp
+++ b/engines/agos/window.cpp
@@ -298,11 +298,11 @@ void AGOSEngine::waitWindow(WindowBlock *window) {
ha->id = 0x7FFF;
ha->priority = 999;
- for (;;) {
+ while (!quit()) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!quit()) {
if (_lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp
index 8dbccebedf..f5cde579e6 100644
--- a/engines/cine/anim.cpp
+++ b/engines/cine/anim.cpp
@@ -49,11 +49,10 @@ struct AnimHeader2Struct {
uint16 field_E;
};
-AnimData animDataTable[NUM_MAX_ANIMDATA];
+Common::Array<AnimData> animDataTable;
static const AnimDataEntry transparencyData[] = {
{"ALPHA", 0xF},
- {"TITRE", 0xF},
{"TITRE2", 0xF},
{"ET", 0xC},
{"L311", 0x3},
@@ -511,14 +510,15 @@ int emptyAnimSpace(int start = 0) {
/*! \brief Load SPL data into animDataTable
* \param resourceName SPL filename
- * \param idx Target index in animDataTable
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded SPL data (-1 if error)
*/
-void loadSpl(const char *resourceName, int16 idx) {
+int loadSpl(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
int entry;
if (foundFileIdx < 0) {
- return;
+ return -1;
}
byte *dataPtr = readBundleFile(foundFileIdx);
@@ -528,13 +528,20 @@ void loadSpl(const char *resourceName, int16 idx) {
animDataTable[entry].load(dataPtr, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName);
free(dataPtr);
+ return entry + 1;
}
/*! \brief Load 1bpp mask
* \param resourceName Mask filename
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded mask (-1 if error)
*/
-void loadMsk(const char *resourceName) {
+int loadMsk(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
int entry = 0;
byte *dataPtr = readBundleFile(foundFileIdx);
byte *ptr;
@@ -544,21 +551,28 @@ void loadMsk(const char *resourceName) {
loadAnimHeader(animHeader, readS);
ptr = dataPtr + 0x16;
+ entry = idx < 0 ? emptyAnimSpace() : idx;
+ assert(entry >= 0);
for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
- entry = emptyAnimSpace(entry);
- assert(entry >= 0);
animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName);
ptr += animHeader.frameWidth * animHeader.frameHeight;
}
free(dataPtr);
+ return entry;
}
/*! \brief Load animation
* \param resourceName Animation filename
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded animation (-1 if error)
*/
-void loadAni(const char *resourceName) {
+int loadAni(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
int entry = 0;
byte *dataPtr = readBundleFile(foundFileIdx);
byte *ptr;
@@ -571,10 +585,18 @@ void loadAni(const char *resourceName) {
transparentColor = getAnimTransparentColor(resourceName);
- for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
- entry = emptyAnimSpace(entry);
- assert(entry >= 0);
+ // TODO: Merge this special case hack into getAnimTransparentColor somehow.
+ // HACK: Versions of TITRE.ANI with height 37 use color 0xF for transparency.
+ // Versions of TITRE.ANI with height 57 use color 0x0 for transparency.
+ // Fixes bug #2057619: FW: Glitches in title display of demo (regression).
+ if (scumm_stricmp(resourceName, "TITRE.ANI") == 0 && animHeader.frameHeight == 37) {
+ transparentColor = 0xF;
+ }
+
+ entry = idx < 0 ? emptyAnimSpace() : idx;
+ assert(entry >= 0);
+ for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
// special case transparency handling
if (!strcmp(resourceName, "L2202.ANI")) {
transparentColor = i < 2 ? 0 : 7;
@@ -587,6 +609,7 @@ void loadAni(const char *resourceName) {
}
free(dataPtr);
+ return entry;
}
/*! \brief Decode 16 color image with palette
@@ -642,16 +665,21 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
/*! \brief Load image set
* \param resourceName Image set filename
- * \param idx Target index in animDataTable
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded image set (-1 if error)
*/
-void loadSet(const char *resourceName, int16 idx) {
+int loadSet(const char *resourceName, int16 idx) {
AnimHeader2Struct header2;
uint16 numSpriteInAnim;
int16 foundFileIdx = findFileInBundle(resourceName);
- int16 entry = idx >= 0 ? idx : 0;
+ int16 entry;
byte *ptr, *startOfDataPtr, *dataPtr, *origDataPtr;
int type;
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
origDataPtr = dataPtr = readBundleFile(foundFileIdx);
assert(!memcmp(dataPtr, "SET", 3));
ptr = dataPtr + 4;
@@ -661,6 +689,9 @@ void loadSet(const char *resourceName, int16 idx) {
startOfDataPtr = ptr + numSpriteInAnim * 0x10;
+ entry = idx < 0 ? emptyAnimSpace() : idx;
+ assert(entry >= 0);
+
for (int16 i = 0; i < numSpriteInAnim; i++, entry++) {
Common::MemoryReadStream readS(ptr, 0x10);
@@ -674,9 +705,6 @@ void loadSet(const char *resourceName, int16 idx) {
ptr += 0x10;
- entry = idx < 0 ? emptyAnimSpace(entry) : idx + i;
- assert(entry >= 0);
-
dataPtr = startOfDataPtr + header2.field_0;
if (header2.type == 1) {
@@ -693,78 +721,59 @@ void loadSet(const char *resourceName, int16 idx) {
}
free(origDataPtr);
+ return entry;
}
/*! \brief Load SEQ data into animDataTable
* \param resourceName SEQ data filename
- * \param idx Target index in animDataTable
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded SEQ data (-1 if error)
*/
-void loadSeq(const char *resourceName, int16 idx) {
+int loadSeq(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
byte *dataPtr = readBundleFile(foundFileIdx);
int entry = idx < 0 ? emptyAnimSpace() : idx;
animDataTable[entry].load(dataPtr+0x16, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize-0x16, 1, foundFileIdx, 0, currentPartName);
free(dataPtr);
+ return entry + 1;
}
-void loadResource(const char *resourceName) {
- /* byte isMask = 0; */
- /* byte isSpl = 0; */
-
+/*! \brief Load a resource into animDataTable
+ * \param resourceName Resource's filename
+ * \param idx Target index in animDataTable (-1 if any empty space will do)
+ * \return The number of the animDataTable entry after the loaded resource (-1 if error)
+ * \todo Implement loading of all resource types
+ */
+int loadResource(const char *resourceName, int16 idx) {
+ int result = -1; // Return an error by default
if (strstr(resourceName, ".SPL")) {
- loadSpl(resourceName, -1);
- return;
+ result = loadSpl(resourceName, idx);
} else if (strstr(resourceName, ".MSK")) {
- loadMsk(resourceName);
- return;
+ result = loadMsk(resourceName, idx);
} else if (strstr(resourceName, ".ANI")) {
- loadAni(resourceName);
- return;
+ result = loadAni(resourceName, idx);
} else if (strstr(resourceName, ".ANM")) {
- loadAni(resourceName);
- return;
+ result = loadAni(resourceName, idx);
} else if (strstr(resourceName, ".SET")) {
- loadSet(resourceName, -1);
- return;
+ result = loadSet(resourceName, idx);
} else if (strstr(resourceName, ".SEQ")) {
- loadSeq(resourceName, -1);
- return;
- } else if (strstr(resourceName, "ECHEC")) { // Echec (French) means failure
- exitEngine = 1;
- return;
- }
-
- error("loadResource: Cannot determine type for '%s'", resourceName);
-}
-
-/*! \todo There seems to be some additional resource file that is not loaded
- */
-void loadAbs(const char *resourceName, uint16 idx) {
- /* byte isMask = 0; */
- /* byte isSpl = 0; */
-
- if (strstr(resourceName, ".SET")) {
- loadSet(resourceName, idx);
- return;
+ result = loadSeq(resourceName, idx);
} else if (strstr(resourceName, ".H32")) {
- warning("Ignoring file %s (load at %d)", resourceName, idx);
- return;
- } else if (strstr(resourceName, ".SEQ")) {
- loadSeq(resourceName, idx);
- return;
- } else if (strstr(resourceName, ".SPL")) {
- loadSpl(resourceName, idx);
- return;
+ warning("loadResource: Ignoring file '%s' (Load at %d)", resourceName, idx);
} else if (strstr(resourceName, ".AMI")) {
- warning("Ignoring file %s (load at %d)", resourceName, idx);
- return;
- } else if (strstr(resourceName, ".ANI")) {
- warning("Ignoring file %s (load at %d)", resourceName, idx);
- return;
+ warning("loadResource: Ignoring file '%s' (Load at %d)", resourceName, idx);
+ } else if (strstr(resourceName, "ECHEC")) { // Echec (French) means failure
+ g_cine->quitGame();
+ } else {
+ error("loadResource: Cannot determine type for '%s'", resourceName);
}
- error("loadAbs: Cannot determine type for '%s'", resourceName);
+ return result;
}
/*! \brief Load animDataTable from save
@@ -776,17 +785,9 @@ void loadAbs(const char *resourceName, uint16 idx) {
* at a time.
*/
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
- int16 currentAnim, foundFileIdx;
- int8 isMask = 0, isSpl = 0;
- byte *dataPtr, *ptr;
- char *animName, part[256];
- byte transparentColor = 0;
- AnimHeaderStruct animHeader;
-
+ int16 currentAnim, foundFileIdx, frame;
+ char *animName, part[256], name[10];
uint16 width, height, bpp, var1;
- int16 frame;
- char name[10];
- int type;
strcpy(part, currentPartName);
@@ -795,11 +796,8 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
const int fileStartPos = fHandle.pos();
- for (currentAnim = 0; currentAnim < NUM_MAX_ANIMDATA; currentAnim += animHeader.numFrames) {
- // Initialize the number of frames variable to a sane number.
- // This is needed when using continue later in this function.
- animHeader.numFrames = 1;
-
+ currentAnim = 0;
+ while (currentAnim < NUM_MAX_ANIMDATA) {
// Seek to the start of the current animation's entry
fHandle.seek(fileStartPos + currentAnim * entrySize);
// Read in the current animation entry
@@ -826,6 +824,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
// Don't try to load invalid entries.
if (foundFileIdx < 0 || !validPtr) {
+ currentAnim++; // Jump over the invalid entry
continue;
}
@@ -836,52 +835,10 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
}
animName = partBuffer[foundFileIdx].partName;
- ptr = dataPtr = readBundleFile(foundFileIdx);
-
- // isSpl and isMask are mutually exclusive cases
- isSpl = (strstr(animName, ".SPL")) ? 1 : 0;
- isMask = (strstr(animName, ".MSK")) ? 1 : 0;
-
- if (isSpl) {
- width = (uint16) partBuffer[foundFileIdx].unpackedSize;
- height = 1;
- animHeader.numFrames = 1;
- type = ANIM_RAW;
- } else {
- Common::MemoryReadStream readS(ptr, 0x16);
- loadAnimHeader(animHeader, readS);
- ptr += 0x16;
-
- width = animHeader.frameWidth;
- height = animHeader.frameHeight;
-
- if (isMask) {
- type = ANIM_MASK;
- } else {
- type = ANIM_MASKSPRITE;
- }
- }
-
- loadRelatedPalette(animName);
- transparentColor = getAnimTransparentColor(animName);
- // Make sure we load at least one frame and also that we
- // don't overflow the animDataTable by writing beyond its end.
- animHeader.numFrames = CLIP<uint16>(animHeader.numFrames, 1, NUM_MAX_ANIMDATA - currentAnim);
-
- // Load the frames
- for (frame = 0; frame < animHeader.numFrames; frame++) {
- // special case transparency handling
- if (!strcmp(animName, "L2202.ANI")) {
- transparentColor = (frame < 2) ? 0 : 7;
- } else if (!strcmp(animName, "L4601.ANI")) {
- transparentColor = (frame < 1) ? 0xE : 0;
- }
-
- // Load a single frame
- animDataTable[currentAnim + frame].load(ptr + frame * width * height, type, width, height, foundFileIdx, frame, name, transparentColor);
- }
-
- free(dataPtr);
+ loadRelatedPalette(animName); // Is this for Future Wars only?
+ const int16 prevAnim = currentAnim;
+ currentAnim = loadResource(animName, currentAnim);
+ assert(currentAnim > prevAnim); // Make sure we advance forward
}
loadPart(part);
diff --git a/engines/cine/anim.h b/engines/cine/anim.h
index b0ce55f7ee..8b1541eb3f 100644
--- a/engines/cine/anim.h
+++ b/engines/cine/anim.h
@@ -150,12 +150,11 @@ public:
#define NUM_MAX_ANIMDATA 255
-extern AnimData animDataTable[NUM_MAX_ANIMDATA];
+extern Common::Array<AnimData> animDataTable;
void freeAnimDataTable(void);
void freeAnimDataRange(byte startIdx, byte numIdx);
-void loadResource(const char *resourceName);
-void loadAbs(const char *resourceName, uint16 idx);
+int loadResource(const char *resourceName, int16 idx = -1);
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat);
void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency);
diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp
index 2a4e7f0ab1..cc7e843c2b 100644
--- a/engines/cine/bg.cpp
+++ b/engines/cine/bg.cpp
@@ -41,10 +41,18 @@ byte loadCtFW(const char *ctName) {
uint16 header[32];
byte *ptr, *dataPtr;
+ int16 foundFileIdx = findFileInBundle(ctName);
+ if (foundFileIdx == -1) {
+ warning("loadCtFW: Unable to find collision data file '%s'", ctName);
+ // FIXME: Rework this function's return value policy and return an appropriate value here.
+ // The return value isn't yet used for anything so currently it doesn't really matter.
+ return 0;
+ }
+
if (currentCtName != ctName)
strcpy(currentCtName, ctName);
- ptr = dataPtr = readBundleFile(findFileInBundle(ctName));
+ ptr = dataPtr = readBundleFile(foundFileIdx);
loadRelatedPalette(ctName);
@@ -56,7 +64,7 @@ byte loadCtFW(const char *ctName) {
header[i] = readS.readUint16BE();
}
- gfxConvertSpriteToRaw(page3Raw, ptr + 0x80, 160, 200);
+ gfxConvertSpriteToRaw(collisionPage, ptr + 0x80, 160, 200);
free(dataPtr);
return 0;
@@ -74,10 +82,10 @@ byte loadCtOS(const char *ctName) {
ptr += 2;
if (bpp == 8) {
- memcpy(page3Raw, ptr + 256 * 3, 320 * 200);
+ memcpy(collisionPage, ptr + 256 * 3, 320 * 200);
renderer->loadCt256(ptr, ctName);
} else {
- gfxConvertSpriteToRaw(page3Raw, ptr + 32, 160, 200);
+ gfxConvertSpriteToRaw(collisionPage, ptr + 32, 160, 200);
renderer->loadCt16(ptr, ctName);
}
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index f6778b6457..2c0fdc7d88 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/events.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/config-manager.h"
@@ -57,6 +56,10 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng
// Setup mixer
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ // Use music volume for plain sound types (At least the Adlib player uses a plain sound type
+ // so previously the music and sfx volume controls didn't affect it at all).
+ // FIXME: Make Adlib player differentiate between playing sound effects and music and remove this.
+ _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("music_volume"));
g_cine = this;
@@ -65,14 +68,9 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng
CineEngine::~CineEngine() {
if (g_cine->getGameType() == Cine::GType_OS) {
- freePoldatDat();
freeErrmessDat();
}
Common::clearAllSpecialDebugLevels();
-
- free(palPtr);
- free(partBuffer);
- free(textDataPtr);
}
int CineEngine::init() {
@@ -100,13 +98,44 @@ int CineEngine::go() {
mainLoop(1);
delete renderer;
- delete[] page3Raw;
+ delete[] collisionPage;
delete g_sound;
+
return 0;
}
+int CineEngine::getTimerDelay() const {
+ return (10923000 * _timerDelayMultiplier) / 1193180;
+}
+
+/*! \brief Modify game speed
+ * \param speedChange Negative values slow game down, positive values speed it up, zero does nothing
+ * \return Timer delay multiplier's value after the game speed change
+ */
+int CineEngine::modifyGameSpeed(int speedChange) {
+ // If we want more speed we decrement the timer delay multiplier and vice versa.
+ _timerDelayMultiplier = CLIP(_timerDelayMultiplier - speedChange, 1, 50);
+ return _timerDelayMultiplier;
+}
void CineEngine::initialize() {
+ // Resize object table to its correct size and reset all its elements
+ objectTable.resize(NUM_MAX_OBJECT);
+ resetObjectTable();
+
+ // Resize animation data table to its correct size and reset all its elements
+ animDataTable.resize(NUM_MAX_ANIMDATA);
+ freeAnimDataTable();
+
+ // Resize zone data table to its correct size and reset all its elements
+ zoneData.resize(NUM_MAX_ZONE);
+ Common::set_to(zoneData.begin(), zoneData.end(), 0);
+
+ // Resize zone query table to its correct size and reset all its elements
+ zoneQuery.resize(NUM_MAX_ZONE);
+ Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0);
+
+ _timerDelayMultiplier = 12; // Set default speed
setupOpcodes();
initLanguage(g_cine->getLanguage());
@@ -117,16 +146,17 @@ void CineEngine::initialize() {
renderer = new FWRenderer;
}
- page3Raw = new byte[320 * 200];
- textDataPtr = (byte *)malloc(8000);
+ collisionPage = new byte[320 * 200];
- partBuffer = (PartBuffer *)malloc(NUM_MAX_PARTDATA * sizeof(PartBuffer));
+ // Clear part buffer as there's nothing loaded into it yet.
+ // Its size will change when loading data into it with the loadPart function.
+ partBuffer.clear();
if (g_cine->getGameType() == Cine::GType_OS) {
readVolCnf();
}
- loadTextData("texte.dat", textDataPtr);
+ loadTextData("texte.dat");
if (g_cine->getGameType() == Cine::GType_OS && !(g_cine->getFeatures() & GF_DEMO)) {
loadPoldatDat("poldat.dat");
@@ -142,8 +172,7 @@ void CineEngine::initialize() {
freeAnimDataTable();
overlayList.clear();
messageTable.clear();
-
- memset(objectTable, 0, sizeof(objectTable));
+ resetObjectTable();
var8 = 0;
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index eaae555812..6011036eb1 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -59,7 +59,8 @@ enum CineGameType {
enum CineGameFeatures {
GF_CD = 1 << 0,
GF_DEMO = 1 << 1,
- GF_ALT_FONT = 1 << 2
+ GF_ALT_FONT = 1 << 2,
+ GF_CRYPTED_BOOT_PRC = 1 << 3
};
struct CINEGameDescription;
@@ -86,6 +87,8 @@ public:
bool loadSaveDirectory(void);
void makeSystemMenu(void);
+ int modifyGameSpeed(int speedChange);
+ int getTimerDelay() const;
const CINEGameDescription *_gameDescription;
Common::File _partFileHandle;
@@ -109,6 +112,7 @@ private:
void readVolCnf();
bool _preLoad;
+ int _timerDelayMultiplier;
};
extern CineEngine *g_cine;
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 8c940bcfd4..91ef964a0b 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -76,6 +76,25 @@ static const CINEGameDescription gameDescriptions[] = {
0,
},
+ // This is a CD version of Future Wars published by Sony.
+ // This version has a crypted AUTO00.PRC.
+ {
+ {
+ "fw",
+ "Sony CD version",
+ {
+ { "AUTO00.PRC", 0, "4fe1e7930b38e3c63f0f2474d471bf8f", -1},
+ { "PART01", 0, "61d003202d301c29dd399acfb1354310", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::EN_USA,
+ Common::kPlatformPC,
+ Common::ADGF_CD
+ },
+ GType_FW,
+ GF_CD | GF_CRYPTED_BOOT_PRC,
+ },
+
{
// This is the version included in the UK "Classic Collection"
{
@@ -251,6 +270,21 @@ static const CINEGameDescription gameDescriptions[] = {
},
{
+ // This is a 16 color PC version (It came on three 720kB 3.5" disks).
+ // The protagonist is named John Glames in this version.
+ {
+ "os",
+ "",
+ AD_ENTRY1("procs1", "9629129b86979fa592c1787385bf3695"),
+ Common::EN_GRB,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ GType_OS,
+ 0,
+ },
+
+ {
{
"os",
"",
@@ -499,8 +533,17 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual SaveStateList listSaves(const char *target) const;
};
+bool CineMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad);
+}
+
bool CineMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Cine::CINEGameDescription *gd = (const Cine::CINEGameDescription *)desc;
if (gd) {
@@ -509,6 +552,50 @@ bool CineMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return gd != 0;
}
+SaveStateList CineMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ SaveStateList saveList;
+
+ Common::String pattern = target;
+ pattern += ".?";
+ Common::StringList filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end());
+ Common::StringList::const_iterator file = filenames.begin();
+
+ Common::String filename = target;
+ filename += ".dir";
+ Common::InSaveFile *in = saveFileMan->openForLoading(filename.c_str());
+ if (in) {
+ int8 ch;
+ char saveDesc[20];
+ do {
+ // Obtain the last digit of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 1);
+
+ uint pos = 0;
+ do {
+ ch = in->readByte();
+ if (pos < (sizeof(saveDesc) - 1)) {
+ if (ch < 32 || in->eos()) {
+ saveDesc[pos++] = '\0';
+ }
+ else if (ch >= 32) {
+ saveDesc[pos++] = ch;
+ }
+ }
+ } while (ch >= 32 && !in->eos());
+ if (saveDesc[0] != 0) {
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ file++;
+ }
+ } while (!in->eos());
+ }
+
+ delete in;
+
+ return saveList;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(CINE)
REGISTER_PLUGIN_DYNAMIC(CINE, PLUGIN_TYPE_ENGINE, CineMetaEngine);
#else
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index cbddf0fc59..e24b23f7f0 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -31,12 +31,13 @@
#include "common/endian.h"
#include "common/system.h"
+#include "common/events.h"
#include "graphics/cursorman.h"
namespace Cine {
-byte *page3Raw;
+byte *collisionPage;
FWRenderer *renderer = NULL;
static const byte mouseCursorNormal[] = {
@@ -91,7 +92,7 @@ static const byte cursorPalette[] = {
*/
FWRenderer::FWRenderer() : _background(NULL), _palette(NULL), _cmd(""),
_cmdY(0), _messageBg(0), _backBuffer(new byte[_screenSize]),
- _activeLowPal(NULL), _changePal(0) {
+ _activeLowPal(NULL), _changePal(0), _showCollisionPage(false) {
assert(_backBuffer);
@@ -125,6 +126,7 @@ void FWRenderer::clear() {
_cmdY = 0;
_messageBg = 0;
_changePal = 0;
+ _showCollisionPage = false;
}
/*! \brief Draw 1bpp sprite using selected color
@@ -198,9 +200,15 @@ void FWRenderer::incrustSprite(const objectStruct &obj) {
width = animDataTable[obj.frame]._realWidth;
height = animDataTable[obj.frame]._height;
- assert(mask);
-
- drawSpriteRaw(data, mask, width, height, _background, x, y);
+ // There was an assert(mask) here before but it made savegame loading
+ // in Future Wars sometimes fail the assertion (e.g. see bug #2055912).
+ // Not drawing sprites that have no mask seems to work, but not sure
+ // if this is really a correct way to fix this.
+ if (mask) {
+ drawSpriteRaw(data, mask, width, height, _background, x, y);
+ } else { // mask == NULL
+ warning("FWRenderer::incrustSprite: Skipping maskless sprite (frame=%d)", obj.frame);
+ }
}
/*! \brief Draw command box on screen
@@ -225,14 +233,18 @@ void FWRenderer::drawCommand() {
* \param x Top left message box corner coordinate
* \param y Top left message box corner coordinate
* \param width Message box width
- * \param color Message box background color
+ * \param color Message box background color (Or if negative draws only the text)
+ * \note Negative colors are used in Operation Stealth's timed cutscenes
+ * (e.g. when first meeting The Movement for the Liberation of Santa Paragua).
*/
-void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte color) {
+void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color) {
int i, tx, ty, tw;
int line = 0, words = 0, cw = 0;
int space = 0, extraSpace = 0;
- drawPlainBox(x, y, width, 4, color);
+ if (color >= 0) {
+ drawPlainBox(x, y, width, 4, color);
+ }
tx = x + 4;
ty = str[0] ? y - 5 : y + 4;
tw = width - 8;
@@ -252,7 +264,9 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo
}
ty += 9;
- drawPlainBox(x, ty, width, 9, color);
+ if (color >= 0) {
+ drawPlainBox(x, ty, width, 9, color);
+ }
tx = x + 4;
}
@@ -269,33 +283,56 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo
}
ty += 9;
- drawPlainBox(x, ty, width, 4, color);
- drawDoubleBorder(x, y, width, ty - y + 4, 2);
+ if (color >= 0) {
+ drawPlainBox(x, ty, width, 4, color);
+ drawDoubleBorder(x, y, width, ty - y + 4, 2);
+ }
}
/*! \brief Draw rectangle on screen
* \param x Top left corner coordinate
* \param y Top left corner coordinate
- * \param width Rectangle width
- * \param height Rectangle height
+ * \param width Rectangle width (Negative values draw the box horizontally flipped)
+ * \param height Rectangle height (Negative values draw the box vertically flipped)
* \param color Fill color
+ * \note An on-screen rectangle's drawn width is always at least one.
+ * \note An on-screen rectangle's drawn height is always at least one.
*/
void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) {
- int i;
- byte *dest = _backBuffer + y * 320 + x;
+ // Make width's and height's absolute values at least one
+ // which forces this function to always draw something if the
+ // drawing position is inside screen bounds. This fixes at least
+ // the showing of the oxygen gauge meter in Operation Stealth's
+ // first arcade sequence where this function is called with a
+ // height of zero.
+ if (width == 0) {
+ width = 1;
+ }
+ if (height == 0) {
+ height = 1;
+ }
+ // Handle horizontally flipped boxes
if (width < 0) {
- x += width;
- width = -width;
+ width = ABS(width);
+ x -= width;
}
+ // Handle vertically flipped boxes
if (height < 0) {
- y += height;
- height = -height;
+ height = ABS(height);
+ y -= height;
}
- for (i = 0; i < height; i++) {
- memset(dest + i * 320, color, width);
+ // Clip the rectangle to screen dimensions
+ Common::Rect boxRect(x, y, x + width, y + height);
+ Common::Rect screenRect(320, 200);
+ boxRect.clip(screenRect);
+
+ // Draw the filled rectangle
+ byte *dest = _backBuffer + boxRect.top * 320 + boxRect.left;
+ for (int i = 0; i < boxRect.height(); i++) {
+ memset(dest + i * 320, color, boxRect.width());
}
}
@@ -335,9 +372,9 @@ int FWRenderer::drawChar(char character, int x, int y) {
if (character == ' ') {
x += 5;
- } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
- idx = fontParamTable[(unsigned char)character].characterIdx;
- drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y);
+ } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) {
+ idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx;
+ drawSpriteRaw(g_cine->_textHandler.textTable[idx][FONT_DATA], g_cine->_textHandler.textTable[idx][FONT_MASK], FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y);
x += width + 1;
}
@@ -405,7 +442,10 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
switch (it->type) {
// color sprite
case 0:
- sprite = animDataTable + objectTable[it->objIdx].frame;
+ if (objectTable[it->objIdx].frame < 0) {
+ return;
+ }
+ sprite = &animDataTable[objectTable[it->objIdx].frame];
len = sprite->_realWidth * sprite->_height;
mask = new byte[len];
memcpy(mask, sprite->mask(), len);
@@ -422,6 +462,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
_messageLen += messageTable[it->objIdx].size();
drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color);
+ waitForPlayerClick = 1;
break;
// action failure message
@@ -433,12 +474,13 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
width = width > 300 ? 300 : width;
drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, 4);
+ waitForPlayerClick = 1;
break;
// bitmap
case 4:
assert(it->objIdx < NUM_MAX_OBJECT);
- obj = objectTable + it->objIdx;
+ obj = &objectTable[it->objIdx];
if (obj->frame < 0) {
return;
@@ -480,16 +522,28 @@ void FWRenderer::drawFrame() {
blit();
}
+/*!
+ * \brief Turn on or off the showing of the collision page.
+ * If turned on the blitting routine shows the collision page instead of the back buffer.
+ * \note Useful for debugging collision page related problems.
+ */
+void FWRenderer::showCollisionPage(bool state) {
+ _showCollisionPage = state;
+}
+
/*! \brief Update screen
*/
void FWRenderer::blit() {
- g_system->copyRectToScreen(_backBuffer, 320, 0, 0, 320, 200);
+ // Show the back buffer or the collision page. Normally the back
+ // buffer but showing the collision page is useful for debugging.
+ byte *source = (_showCollisionPage ? collisionPage : _backBuffer);
+ g_system->copyRectToScreen(source, 320, 0, 0, 320, 200);
}
/*! \brief Set player command string
* \param cmd New command string
*/
-void FWRenderer::setCommand(const char *cmd) {
+void FWRenderer::setCommand(Common::String cmd) {
_cmd = cmd;
}
@@ -617,6 +671,11 @@ void FWRenderer::saveBgNames(Common::OutSaveFile &fHandle) {
fHandle.write(_bgName, 13);
}
+const char *FWRenderer::getBgName(uint idx) const {
+ assert(idx == 0);
+ return _bgName;
+}
+
/*! \brief Restore active and backup palette from save
* \param fHandle Savefile open for reading
*/
@@ -985,9 +1044,9 @@ int OSRenderer::drawChar(char character, int x, int y) {
if (character == ' ') {
x += 5;
- } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) {
- idx = fontParamTable[(unsigned char)character].characterIdx;
- drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y);
+ } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) {
+ idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx;
+ drawSpriteRaw2(g_cine->_textHandler.textTable[idx][FONT_DATA], 0, FONT_WIDTH, FONT_HEIGHT, _backBuffer, x, y);
x += width + 1;
}
@@ -1011,8 +1070,12 @@ void OSRenderer::drawBackground() {
assert(scroll);
- memcpy(_backBuffer, main + mainShift, mainSize);
- memcpy(_backBuffer + mainSize, scroll, mainShift);
+ if (mainSize > 0) { // Just a precaution
+ memcpy(_backBuffer, main + mainShift, mainSize);
+ }
+ if (mainShift > 0) { // Just a precaution
+ memcpy(_backBuffer + mainSize, scroll, mainShift);
+ }
}
}
@@ -1021,10 +1084,11 @@ void OSRenderer::drawBackground() {
* \todo Add handling of type 22 overlays
*/
void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
- int len;
+ int len, idx, width, height;
objectStruct *obj;
AnimData *sprite;
byte *mask;
+ byte color;
switch (it->type) {
// color sprite
@@ -1032,7 +1096,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
if (objectTable[it->objIdx].frame < 0) {
break;
}
- sprite = animDataTable + objectTable[it->objIdx].frame;
+ sprite = &animDataTable[objectTable[it->objIdx].frame];
len = sprite->_realWidth * sprite->_height;
mask = new byte[len];
generateMask(sprite->data(), mask, len, objectTable[it->objIdx].part);
@@ -1041,6 +1105,32 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
delete[] mask;
break;
+ // game message
+ case 2:
+ if (it->objIdx >= messageTable.size()) {
+ return;
+ }
+
+ _messageLen += messageTable[it->objIdx].size();
+ drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color);
+ if (it->color >= 0) { // This test isn't in Future Wars's implementation
+ waitForPlayerClick = 1;
+ }
+ break;
+
+ // action failure message
+ case 3:
+ idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3);
+ len = strlen(failureMessages[idx]);
+ _messageLen += len;
+ width = 6 * len + 20;
+ width = width > 300 ? 300 : width;
+
+ // The used color here differs from Future Wars
+ drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, _messageBg);
+ waitForPlayerClick = 1;
+ break;
+
// bitmap
case 4:
if (objectTable[it->objIdx].frame >= 0) {
@@ -1051,16 +1141,37 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
// masked background
case 20:
assert(it->objIdx < NUM_MAX_OBJECT);
- obj = objectTable + it->objIdx;
- sprite = animDataTable + obj->frame;
+ var5 = it->x; // A global variable updated here!
+ obj = &objectTable[it->objIdx];
+ sprite = &animDataTable[obj->frame];
- if (obj->frame < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) {
+ if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) {
break;
}
maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y);
break;
+ // FIXME: Implement correct drawing of type 21 overlays.
+ // Type 21 overlays aren't just filled rectangles, I found their drawing routine
+ // from Operation Stealth's drawSprite routine. So they're likely some kind of sprites
+ // and it's just a coincidence that the oxygen meter during the first arcade sequence
+ // works even somehow currently. I tried the original under DOSBox and the oxygen gauge
+ // is a long red bar that gets shorter as the air runs out.
+ case 21:
+ // A filled rectangle:
+ case 22:
+ // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing).
+ assert(it->objIdx < NUM_MAX_OBJECT);
+ obj = &objectTable[it->objIdx];
+ color = obj->part & 0x0F;
+ width = obj->frame;
+ height = obj->costume;
+ drawPlainBox(obj->x, obj->y, width, height, color);
+ debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d",
+ it->type, obj->x, obj->y, width, height, color);
+ break;
+
// something else
default:
FWRenderer::renderOverlay(it);
@@ -1332,6 +1443,11 @@ void OSRenderer::saveBgNames(Common::OutSaveFile &fHandle) {
}
}
+const char *OSRenderer::getBgName(uint idx) const {
+ assert(idx < 9);
+ return _bgTable[idx].name;
+}
+
/*! \brief Fade to black
* \bug Operation Stealth sometimes seems to fade to black using
* transformPalette resulting in double fadeout
@@ -1557,6 +1673,16 @@ void gfxResetRawPage(byte *pageRaw) {
}
void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h) {
+ // Output is 4 bits per pixel.
+ // Pixels are in 16 pixel chunks (8 bytes of source per 16 pixels of output).
+ // The source data is interleaved so that
+ // 1st big-endian 16-bit value contains all bit position 0 values for 16 pixels,
+ // 2nd big-endian 16-bit value contains all bit position 1 values for 16 pixels,
+ // 3rd big-endian 16-bit value contains all bit position 2 values for 16 pixels,
+ // 4th big-endian 16-bit value contains all bit position 3 values for 16 pixels.
+ // 1st pixel's bits are in the 16th bits,
+ // 2nd pixel's bits are in the 15th bits,
+ // 3rd pixel's bits are in the 14th bits etc.
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w / 8; ++x) {
for (int bit = 0; bit < 16; ++bit) {
diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h
index 6a3aa1ef89..c07214028c 100644
--- a/engines/cine/gfx.h
+++ b/engines/cine/gfx.h
@@ -62,13 +62,14 @@ protected:
byte *_backBuffer; ///< Screen backbuffer
uint16 *_activeLowPal; ///< Active 16 color palette
int _changePal; ///< Load active palette to video backend on next frame
+ bool _showCollisionPage; ///< Should we show the collision page instead of the back buffer? Used for debugging.
void fillSprite(const objectStruct &obj, uint8 color = 0);
void drawMaskedSprite(const objectStruct &obj, const byte *mask);
virtual void drawSprite(const objectStruct &obj);
void drawCommand();
- void drawMessage(const char *str, int x, int y, int width, byte color);
+ void drawMessage(const char *str, int x, int y, int width, int color);
void drawPlainBox(int x, int y, int width, int height, byte color);
void drawBorder(int x, int y, int width, int height, byte color);
void drawDoubleBorder(int x, int y, int width, int height, byte color);
@@ -94,7 +95,7 @@ public:
void drawFrame();
void blit();
- void setCommand(const char *cmd);
+ void setCommand(Common::String cmd);
virtual void incrustMask(const objectStruct &obj, uint8 color = 0);
virtual void incrustSprite(const objectStruct &obj);
@@ -111,6 +112,7 @@ public:
virtual uint getScroll() const;
virtual void removeBg(unsigned int idx);
virtual void saveBgNames(Common::OutSaveFile &fHandle);
+ virtual const char *getBgName(uint idx = 0) const;
virtual void refreshPalette();
virtual void reloadPalette();
@@ -123,6 +125,7 @@ public:
void drawInputBox(const char *info, const char *input, int cursor, int x, int y, int width);
virtual void fadeToBlack();
+ void showCollisionPage(bool state);
};
/*! \brief Operation Stealth renderer
@@ -168,6 +171,7 @@ public:
uint getScroll() const;
void removeBg(unsigned int idx);
void saveBgNames(Common::OutSaveFile &fHandle);
+ const char *getBgName(uint idx = 0) const;
void refreshPalette();
void reloadPalette();
@@ -181,7 +185,7 @@ public:
void gfxDrawSprite(byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy);
-extern byte *page3Raw;
+extern byte *collisionPage;
extern FWRenderer *renderer;
void setMouseCursor(int cursor);
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index e5e670c973..04c6f5c769 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -25,7 +25,6 @@
#include "common/scummsys.h"
-#include "common/events.h"
#include "common/system.h"
#include "cine/main_loop.h"
@@ -61,9 +60,6 @@ static void processEvent(Common::Event &event) {
break;
case Common::EVENT_MOUSEMOVE:
break;
- case Common::EVENT_QUIT:
- exitEngine = 1;
- break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
case Common::KEYCODE_RETURN:
@@ -125,11 +121,74 @@ static void processEvent(Common::Event &event) {
g_cine->makeSystemMenu();
}
break;
+ case Common::KEYCODE_F11:
+ renderer->showCollisionPage(true);
+ break;
+ case Common::KEYCODE_MINUS:
+ case Common::KEYCODE_KP_MINUS:
+ g_cine->modifyGameSpeed(-1); // Slower
+ break;
+ case Common::KEYCODE_PLUS:
+ case Common::KEYCODE_KP_PLUS:
+ g_cine->modifyGameSpeed(+1); // Faster
+ break;
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_KP4:
+ moveUsingKeyboard(-1, 0); // Left
+ break;
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_KP6:
+ moveUsingKeyboard(+1, 0); // Right
+ break;
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_KP8:
+ moveUsingKeyboard(0, +1); // Up
+ break;
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_KP2:
+ moveUsingKeyboard(0, -1); // Down
+ break;
+ case Common::KEYCODE_KP9:
+ moveUsingKeyboard(+1, +1); // Up & Right
+ break;
+ case Common::KEYCODE_KP7:
+ moveUsingKeyboard(-1, +1); // Up & Left
+ break;
+ case Common::KEYCODE_KP1:
+ moveUsingKeyboard(-1, -1); // Down & Left
+ break;
+ case Common::KEYCODE_KP3:
+ moveUsingKeyboard(+1, -1); // Down & Right
+ break;
default:
lastKeyStroke = event.kbd.keycode;
break;
}
break;
+ case Common::EVENT_KEYUP:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_F11:
+ renderer->showCollisionPage(false);
+ break;
+ case Common::KEYCODE_KP5: // Emulated left mouse button click
+ case Common::KEYCODE_LEFT: // Left
+ case Common::KEYCODE_KP4: // Left
+ case Common::KEYCODE_RIGHT: // Right
+ case Common::KEYCODE_KP6: // Right
+ case Common::KEYCODE_UP: // Up
+ case Common::KEYCODE_KP8: // Up
+ case Common::KEYCODE_DOWN: // Down
+ case Common::KEYCODE_KP2: // Down
+ case Common::KEYCODE_KP9: // Up & Right
+ case Common::KEYCODE_KP7: // Up & Left
+ case Common::KEYCODE_KP1: // Down & Left
+ case Common::KEYCODE_KP3: // Down & Right
+ // Stop ego movement made with keyboard when releasing a known key
+ moveUsingKeyboard(0, 0);
+ break;
+ default:
+ break;
+ }
default:
break;
}
@@ -138,7 +197,7 @@ static void processEvent(Common::Event &event) {
void manageEvents() {
Common::EventManager *eventMan = g_system->getEventManager();
- uint32 nextFrame = g_system->getMillis() + kGameTimerDelay * kGameSpeed;
+ uint32 nextFrame = g_system->getMillis() + g_cine->getTimerDelay();
do {
Common::Event event;
while (eventMan->pollEvent(event)) {
@@ -195,13 +254,9 @@ void purgeSeqList() {
void CineEngine::mainLoop(int bootScriptIdx) {
bool playerAction;
- uint16 quitFlag;
byte di;
uint16 mouseButton;
- quitFlag = 0;
- exitEngine = 0;
-
if (_preLoad == false) {
resetBgIncrustList();
@@ -227,7 +282,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
menuCommandLen = 0;
playerCommand = -1;
- strcpy(commandBuffer, "");
+ commandBuffer = "";
globalVars[VAR_MOUSE_X_POS] = 0;
globalVars[VAR_MOUSE_Y_POS] = 0;
@@ -247,14 +302,44 @@ void CineEngine::mainLoop(int bootScriptIdx) {
}
do {
+ // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence.
+ // This makes it possible to pass the arcade sequence for now.
+ // FIXME: Remove the hack and make the first arcade sequence normally playable.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ Common::String bgName(renderer->getBgName());
+ // Check if the background is one of the three backgrounds
+ // that are only used during the first arcade sequence.
+ if (bgName == "28.PI1" || bgName == "29.PI1" || bgName == "30.PI1") {
+ static const uint oxygenObjNum = 202, maxOxygen = 264;
+ // Force the amount of oxygen left to the maximum.
+ objectTable[oxygenObjNum].x = maxOxygen;
+ }
+ }
+
+ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck.
+ // After the first arcade sequence the player comes up stairs from
+ // the water in Santa Paragua's downtown in front of the flower shop.
+ // Previously he was completely stuck after getting up the stairs.
+ // If the background is the one used in the flower shop scene ("21.PI1")
+ // and the player is at the exact location after getting up the stairs
+ // then we just nudge him a tiny bit away from the stairs and voila, he's free!
+ // Maybe the real problem behind all this is collision data related as it looks
+ // like there's some boundary right there near position (204, 110) which we can
+ // jump over by moving the character to (204, 109). The script handling the
+ // flower shop scene is AIRPORT.PRC's 13th script.
+ // FIXME: Remove the hack and solve what's really causing the problem in the first place.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ if (scumm_stricmp(renderer->getBgName(), "21.PI1") == 0 && objectTable[1].x == 204 && objectTable[1].y == 110) {
+ objectTable[1].y--; // Move the player character upward on-screen by one pixel
+ }
+ }
+
stopMusicAfterFadeOut();
di = executePlayerInput();
// Clear the zoneQuery table (Operation Stealth specific)
if (g_cine->getGameType() == Cine::GType_OS) {
- for (uint i = 0; i < NUM_MAX_ZONE; i++) {
- zoneQuery[i] = 0;
- }
+ Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0);
}
if (g_cine->getGameType() == Cine::GType_OS) {
@@ -279,6 +364,11 @@ void CineEngine::mainLoop(int bootScriptIdx) {
renderer->drawFrame();
}
+ // NOTE: In the original Future Wars and Operation Stealth messages
+ // were removed when running the drawOverlays function which is
+ // currently called from the renderer's drawFrame function.
+ removeMessages();
+
if (waitForPlayerClick) {
playerAction = false;
@@ -308,8 +398,6 @@ void CineEngine::mainLoop(int bootScriptIdx) {
} while (mouseButton != 0);
waitForPlayerClick = 0;
-
- removeMessages();
}
if (checkForPendingDataLoadSwitch) {
@@ -322,7 +410,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
if ("quit"[menuCommandLen] == (char)di) {
++menuCommandLen;
if (menuCommandLen == 4) {
- quitFlag = 1;
+ quitGame();
}
} else {
menuCommandLen = 0;
@@ -331,7 +419,7 @@ void CineEngine::mainLoop(int bootScriptIdx) {
manageEvents();
- } while (!exitEngine && !quitFlag && _danKeysPressed != 7);
+ } while (!quit() && _danKeysPressed != 7);
hideMouse();
g_sound->stopMusic();
diff --git a/engines/cine/main_loop.h b/engines/cine/main_loop.h
index a2f828fd34..c729b324ca 100644
--- a/engines/cine/main_loop.h
+++ b/engines/cine/main_loop.h
@@ -28,11 +28,6 @@
namespace Cine {
-enum {
- kGameTimerDelay = 1000 / (1193180 / 10923),
- kGameSpeed = 12
-};
-
void mainLoop(int bootScriptIdx);
void manageEvents();
diff --git a/engines/cine/msg.cpp b/engines/cine/msg.cpp
index 55eb627309..c826db3bf3 100644
--- a/engines/cine/msg.cpp
+++ b/engines/cine/msg.cpp
@@ -34,29 +34,40 @@ namespace Cine {
Common::StringList messageTable;
void loadMsg(char *pMsgName) {
- int i, count, len;
- byte *ptr, *dataPtr;
- const char *messagePtr;
+ uint32 sourceSize;
checkDataDisk(-1);
-
messageTable.clear();
-
- ptr = dataPtr = readBundleFile(findFileInBundle(pMsgName));
+ byte *dataPtr = readBundleFile(findFileInBundle(pMsgName), &sourceSize);
setMouseCursor(MOUSE_CURSOR_DISK);
- count = READ_BE_UINT16(ptr);
- ptr += 2;
-
- messagePtr = (const char*)(ptr + 2 * count);
-
- for (i = 0; i < count; i++) {
- len = READ_BE_UINT16(ptr);
- ptr += 2;
-
- messageTable.push_back(messagePtr);
- messagePtr += len;
+ uint count = READ_BE_UINT16(dataPtr);
+ uint messageLenPos = 2;
+ uint messageDataPos = messageLenPos + 2 * count;
+
+ // Read in the messages
+ for (uint i = 0; i < count; i++) {
+ // Read message's length
+ uint messageLen = READ_BE_UINT16(dataPtr + messageLenPos);
+ messageLenPos += 2;
+
+ // Store the read message.
+ // This code works around input data that has empty strings residing outside the input
+ // buffer (e.g. message indexes 58-254 in BATEAU.MSG in PROCS08 in Operation Stealth).
+ if (messageDataPos < sourceSize) {
+ messageTable.push_back((const char *)(dataPtr + messageDataPos));
+ } else {
+ if (messageLen > 0) { // Only warn about overflowing non-empty strings
+ warning("loadMsg(%s): message (%d. / %d) is overflowing the input buffer. Replacing it with an empty string", pMsgName, i + 1, count);
+ } else {
+ debugC(5, kCineDebugPart, "loadMsg(%s): empty message (%d. / %d) resides outside input buffer", pMsgName, i + 1, count);
+ }
+ // Message resides outside the input buffer so we replace it with an empty string
+ messageTable.push_back("");
+ }
+ // Jump to the next message
+ messageDataPos += messageLen;
}
free(dataPtr);
diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp
index c02e01c8ce..9781975f7c 100644
--- a/engines/cine/object.cpp
+++ b/engines/cine/object.cpp
@@ -35,9 +35,16 @@
namespace Cine {
-objectStruct objectTable[NUM_MAX_OBJECT];
+Common::Array<objectStruct> objectTable;
Common::List<overlay> overlayList;
+/*! \brief Resets all elements in the object table. */
+void resetObjectTable() {
+ for (Common::Array<objectStruct>::iterator it = objectTable.begin(); it != objectTable.end(); it++) {
+ it->clear();
+ }
+}
+
void loadObject(char *pObjectName) {
uint16 numEntry;
uint16 entrySize;
diff --git a/engines/cine/object.h b/engines/cine/object.h
index 7ad65eb75f..3bf6cdcc42 100644
--- a/engines/cine/object.h
+++ b/engines/cine/object.h
@@ -38,6 +38,17 @@ struct objectStruct {
int16 costume;
char name[20];
uint16 part;
+
+ /*! \brief Sets all member variables to zero. */
+ void clear() {
+ this->x = 0;
+ this->y = 0;
+ this->mask = 0;
+ this->frame = 0;
+ this->costume = 0;
+ memset(this->name, 0, sizeof(this->name));
+ this->part = 0;
+ }
};
struct overlay {
@@ -52,10 +63,10 @@ struct overlay {
#define NUM_MAX_OBJECT 255
#define NUM_MAX_VAR 255
-extern objectStruct objectTable[NUM_MAX_OBJECT];
-
+extern Common::Array<objectStruct> objectTable;
extern Common::List<overlay> overlayList;
+void resetObjectTable();
void loadObject(char *pObjectName);
void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4);
void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue);
diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp
index 3e6f5adf40..7f6307c640 100644
--- a/engines/cine/pal.cpp
+++ b/engines/cine/pal.cpp
@@ -28,10 +28,7 @@
namespace Cine {
-uint16 palEntriesCount;
-
-PalEntry *palPtr = NULL;
-
+Common::Array<PalEntry> palArray;
static byte paletteBuffer1[16];
static byte paletteBuffer2[16];
@@ -41,27 +38,20 @@ void loadPal(const char *fileName) {
removeExtention(buffer, fileName);
strcat(buffer, ".PAL");
-
- if (palPtr) {
- free(palPtr);
- palPtr = NULL;
- }
-
- palEntriesCount = 0;
+ palArray.clear();
Common::File palFileHandle;
if (!palFileHandle.open(buffer))
error("loadPal(): Cannot open file %s", fileName);
- palEntriesCount = palFileHandle.readUint16LE();
+ uint16 palEntriesCount = palFileHandle.readUint16LE();
palFileHandle.readUint16LE(); // entry size
- palPtr = (PalEntry *)malloc(palEntriesCount * sizeof(PalEntry));
- assert(palPtr);
- for (int i = 0; i < palEntriesCount; ++i) {
- palFileHandle.read(palPtr[i].name, 10);
- palFileHandle.read(palPtr[i].pal1, 16);
- palFileHandle.read(palPtr[i].pal2, 16);
+ palArray.resize(palEntriesCount);
+ for (uint i = 0; i < palArray.size(); ++i) {
+ palFileHandle.read(palArray[i].name, 10);
+ palFileHandle.read(palArray[i].pal1, 16);
+ palFileHandle.read(palArray[i].pal2, 16);
}
palFileHandle.close();
}
@@ -81,8 +71,8 @@ int16 findPaletteFromName(const char *fileName) {
position++;
}
- for (i = 0; i < palEntriesCount; i++) {
- if (!strcmp(buffer, palPtr[i].name)) {
+ for (i = 0; i < palArray.size(); i++) {
+ if (!strcmp(buffer, palArray[i].name)) {
return i;
}
}
@@ -105,9 +95,9 @@ void loadRelatedPalette(const char *fileName) {
paletteBuffer1[i] = paletteBuffer2[i] = (i << 4) + i;
}
} else {
- assert(paletteIndex < palEntriesCount);
- memcpy(paletteBuffer1, palPtr[paletteIndex].pal1, 16);
- memcpy(paletteBuffer2, palPtr[paletteIndex].pal2, 16);
+ assert(paletteIndex < (int32)palArray.size());
+ memcpy(paletteBuffer1, palArray[paletteIndex].pal1, 16);
+ memcpy(paletteBuffer2, palArray[paletteIndex].pal2, 16);
}
}
diff --git a/engines/cine/pal.h b/engines/cine/pal.h
index 768cf0d27d..819680973c 100644
--- a/engines/cine/pal.h
+++ b/engines/cine/pal.h
@@ -34,7 +34,7 @@ struct PalEntry {
byte pal2[16];
};
-extern PalEntry *palPtr;
+extern Common::Array<PalEntry> palArray;
void loadPal(const char *fileName);
diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp
index 88f2dcef52..7679d9d380 100644
--- a/engines/cine/part.cpp
+++ b/engines/cine/part.cpp
@@ -31,13 +31,10 @@
namespace Cine {
-uint16 numElementInPart;
-
-PartBuffer *partBuffer;
+Common::Array<PartBuffer> partBuffer;
void loadPart(const char *partName) {
- memset(partBuffer, 0, sizeof(PartBuffer) * NUM_MAX_PARTDATA);
- numElementInPart = 0;
+ partBuffer.clear();
g_cine->_partFileHandle.close();
@@ -48,13 +45,14 @@ void loadPart(const char *partName) {
setMouseCursor(MOUSE_CURSOR_DISK);
- numElementInPart = g_cine->_partFileHandle.readUint16BE();
+ uint16 numElementInPart = g_cine->_partFileHandle.readUint16BE();
+ partBuffer.resize(numElementInPart);
g_cine->_partFileHandle.readUint16BE(); // entry size
if (currentPartName != partName)
strcpy(currentPartName, partName);
- for (uint16 i = 0; i < numElementInPart; i++) {
+ for (uint16 i = 0; i < partBuffer.size(); i++) {
g_cine->_partFileHandle.read(partBuffer[i].partName, 14);
partBuffer[i].offset = g_cine->_partFileHandle.readUint32BE();
partBuffer[i].packedSize = g_cine->_partFileHandle.readUint32BE();
@@ -125,13 +123,13 @@ void CineEngine::readVolCnf() {
unpackedSize = packedSize = f.size();
}
uint8 *buf = new uint8[unpackedSize];
- f.read(buf, packedSize);
- if (packedSize != unpackedSize) {
- CineUnpacker cineUnpacker;
- if (!cineUnpacker.unpack(buf, packedSize, buf, unpackedSize)) {
- error("Error while unpacking 'vol.cnf' data");
- }
+ uint8 *packedBuf = new uint8[packedSize];
+ f.read(packedBuf, packedSize);
+ CineUnpacker cineUnpacker;
+ if (!cineUnpacker.unpack(packedBuf, packedSize, buf, unpackedSize)) {
+ error("Error while unpacking 'vol.cnf' data");
}
+ delete[] packedBuf;
uint8 *p = buf;
int resourceFilesCount = READ_BE_UINT16(p); p += 2;
int entrySize = READ_BE_UINT16(p); p += 2;
@@ -190,7 +188,7 @@ void CineEngine::readVolCnf() {
int16 findFileInBundle(const char *fileName) {
if (g_cine->getGameType() == Cine::GType_OS) {
// look first in currently loaded resource file
- for (int i = 0; i < numElementInPart; i++) {
+ for (uint i = 0; i < partBuffer.size(); i++) {
if (!scumm_stricmp(fileName, partBuffer[i].partName)) {
return i;
}
@@ -204,7 +202,7 @@ int16 findFileInBundle(const char *fileName) {
const char *part = (*it)._value;
loadPart(part);
}
- for (int i = 0; i < numElementInPart; i++) {
+ for (uint i = 0; i < partBuffer.size(); i++) {
if (!scumm_stricmp(fileName, partBuffer[i].partName)) {
return i;
}
@@ -212,26 +210,32 @@ int16 findFileInBundle(const char *fileName) {
return -1;
}
-void readFromPart(int16 idx, byte *dataPtr) {
+void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) {
+ assert(maxSize >= partBuffer[idx].packedSize);
setMouseCursor(MOUSE_CURSOR_DISK);
g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET);
g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize);
}
-byte *readBundleFile(int16 foundFileIdx) {
- assert(foundFileIdx >= 0 && foundFileIdx < numElementInPart);
+byte *readBundleFile(int16 foundFileIdx, uint32 *size) {
+ assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size());
+ bool error = false;
byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1);
- if (partBuffer[foundFileIdx].unpackedSize != partBuffer[foundFileIdx].packedSize) {
- byte *unpackBuffer = (byte *)malloc(partBuffer[foundFileIdx].packedSize);
- readFromPart(foundFileIdx, unpackBuffer);
- CineUnpacker cineUnpacker;
- if (!cineUnpacker.unpack(unpackBuffer, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize)) {
- warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName);
- }
- free(unpackBuffer);
- } else {
- readFromPart(foundFileIdx, dataPtr);
+ byte *packedData = (byte *)calloc(partBuffer[foundFileIdx].packedSize, 1);
+ assert(dataPtr && packedData);
+ readFromPart(foundFileIdx, packedData, partBuffer[foundFileIdx].packedSize);
+ CineUnpacker cineUnpacker;
+ error = !cineUnpacker.unpack(packedData, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize);
+ free(packedData);
+
+ if (error) {
+ warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName);
+ }
+
+ // Set the size variable if a pointer to it has been given
+ if (size != NULL) {
+ *size = partBuffer[foundFileIdx].unpackedSize;
}
return dataPtr;
@@ -259,7 +263,13 @@ byte *readBundleSoundFile(const char *entryName, uint32 *size) {
return data;
}
-byte *readFile(const char *filename) {
+/*! \brief Rotate byte value to the left by n bits */
+byte rolByte(byte value, uint n) {
+ n %= 8;
+ return (byte) ((value << n) | (value >> (8 - n)));
+}
+
+byte *readFile(const char *filename, bool crypted) {
Common::File in;
in.open(filename);
@@ -272,6 +282,16 @@ byte *readFile(const char *filename) {
byte *dataPtr = (byte *)malloc(size);
in.read(dataPtr, size);
+ // The Sony published CD version of Future Wars has its
+ // AUTO00.PRC file's bytes rotated to the right by one.
+ // So we decode the so called crypting by rotating all
+ // the bytes to the left by one.
+ if (crypted) {
+ for (uint index = 0; index < size; index++) {
+ dataPtr[index] = rolByte(dataPtr[index], 1);
+ }
+ }
+
return dataPtr;
}
@@ -284,7 +304,7 @@ void dumpBundle(const char *fileName) {
strcpy(tmpPart, currentPartName);
loadPart(fileName);
- for (int i = 0; i < numElementInPart; i++) {
+ for (uint i = 0; i < partBuffer.size(); i++) {
byte *data = readBundleFile(i);
debug(0, "%s", partBuffer[i].partName);
diff --git a/engines/cine/part.h b/engines/cine/part.h
index 2a979e4879..755f843b4a 100644
--- a/engines/cine/part.h
+++ b/engines/cine/part.h
@@ -37,18 +37,18 @@ struct PartBuffer {
#define NUM_MAX_PARTDATA 255
-extern PartBuffer *partBuffer;
+extern Common::Array<PartBuffer> partBuffer;
void loadPart(const char *partName);
void closePart(void);
int16 findFileInBundle(const char *fileName);
-void readFromPart(int16 idx, byte *dataPtr);
+void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize);
-byte *readBundleFile(int16 foundFileIdx);
+byte *readBundleFile(int16 foundFileIdx, uint32 *size = NULL);
byte *readBundleSoundFile(const char *entryName, uint32 *size = 0);
-byte *readFile(const char *filename);
+byte *readFile(const char *filename, bool crypted = false);
void checkDataDisk(int16 param);
diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp
index 27b1044620..797a354c4f 100644
--- a/engines/cine/prc.cpp
+++ b/engines/cine/prc.cpp
@@ -25,6 +25,7 @@
#include "common/endian.h"
+#include "common/events.h"
#include "cine/cine.h"
#include "cine/various.h"
@@ -54,14 +55,16 @@ bool loadPrc(const char *pPrcName) {
// This is copy protection. Used to hang the machine
if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) {
- exitEngine = 1;
+ Common::Event event;
+ event.type = Common::EVENT_RTL;
+ g_system->getEventManager()->pushEvent(event);
return false;
}
checkDataDisk(-1);
if ((g_cine->getGameType() == Cine::GType_FW) &&
(!scumm_stricmp(pPrcName, BOOT_PRC_NAME) || !scumm_stricmp(pPrcName, "demo.prc"))) {
- scriptPtr = dataPtr = readFile(pPrcName);
+ scriptPtr = dataPtr = readFile(pPrcName, (g_cine->getFeatures() & GF_CRYPTED_BOOT_PRC) != 0);
} else {
scriptPtr = dataPtr = readBundleFile(findFileInBundle(pPrcName));
}
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index e761a0c8e4..6c13647ff3 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -1319,6 +1319,7 @@ int FWScript::o1_loadBg() {
return 0;
}
+/*! \brief Load collision table data */
int FWScript::o1_loadCt() {
const char *param = getNextString();
@@ -1500,7 +1501,18 @@ int FWScript::o1_compareGlobalVar() {
debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value);
- _compare = compareVars(_globalVars[varIdx], value);
+ // WORKAROUND for bug #2054882. Without this, the monks will always
+ // kill you as an impostor, even if you enter the monastery in disguise.
+ //
+ // TODO: Check whether this might be worked around in some other way
+ // like setting global variable 255 to 143 in Future Wars (This is
+ // supposedly what Future Wars checks for from time to time during
+ // gameplay to verify that copy protection was successfully passed).
+ if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) {
+ _compare = kCmpEQ;
+ } else {
+ _compare = compareVars(_globalVars[varIdx], value);
+ }
}
return 0;
@@ -1789,7 +1801,14 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI
int16 result = 0;
for (int16 i = 0; i < numZones; i++) {
- idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320);
+ // Don't try to read data in Operation Stealth if position isn't in 320x200 screen bounds.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ if ((lx + i) < 0 || (lx + i) > 319 || ly < 0 || ly > 199) {
+ continue;
+ }
+ }
+
+ idx = getZoneFromPositionRaw(collisionPage, lx + i, ly, 320);
assert(idx >= 0 && idx < NUM_MAX_ZONE);
diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp
index a764281758..e8f16ebfcc 100644
--- a/engines/cine/script_os.cpp
+++ b/engines/cine/script_os.cpp
@@ -365,6 +365,7 @@ FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index, const
// OPERATION STEALTH opcodes
// ------------------------------------------------------------------------
+/*! \brief Load collision table data */
int FWScript::o2_loadCt() {
const char *param = getNextString();
@@ -636,7 +637,28 @@ int FWScript::o2_loadAbs() {
const char *param2 = getNextString();
debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2);
- loadAbs(param2, param1);
+ // Load the resource to an absolute position
+ if (loadResource(param2, param1) == -1) { // Check if the loading failed
+ // WORKAROUND: In the 256 color PC version of Operation Stealth when
+ // walking out of the airport in Santa Paragua to the street the
+ // player character should be seen as a grey silhuette while walking
+ // behind the glass. But actually the player character is completely
+ // invisible when walking behind the glass because the animation files
+ // used are wrongly loaded. In AIRPORT.PRC's 6th script there are
+ // calls loadAbs("JOHN01.ANI", 73) and loadAbs("JOHN02.ANI", 37) to
+ // load the animations involved but no such files are found with the
+ // game. Corresponding SET-files are found though. As it worked and
+ // looked fine when I tried loading them instead of the missing ANI
+ // files I'm doing so here. NOTE: At least the German Amiga version
+ // of Operation Stealth seems to have all the files involved
+ // (JOHN01.ANI, JOHN02.ANI, JOHN01.SET and JOHN02.SET).
+ if (scumm_stricmp(param2, "JOHN01.ANI") == 0 && param1 == 73) {
+ loadResource("JOHN01.SET", param1);
+ } else if (scumm_stricmp(param2, "JOHN02.ANI") == 0 && param1 == 37) {
+ loadResource("JOHN02.SET", param1);
+ }
+ }
+
return 0;
}
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index f26032fe98..164c5a9ca5 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -79,13 +79,13 @@ const int PCSoundDriver::_noteTable[] = {
const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable);
struct AdlibRegisterSoundInstrument {
- uint16 vibrato;
- uint16 attackDecay;
- uint16 sustainRelease;
- uint16 feedbackStrength;
- uint16 keyScaling;
- uint16 outputLevel;
- uint16 freqMod;
+ uint8 vibrato;
+ uint8 attackDecay;
+ uint8 sustainRelease;
+ uint8 feedbackStrength;
+ uint8 keyScaling;
+ uint8 outputLevel;
+ uint8 freqMod;
};
struct AdlibSoundInstrument {
@@ -604,6 +604,7 @@ bool PCSoundFxPlayer::load(const char *song) {
_instrumentsData[i] = NULL;
char instrument[64];
+ memset(instrument, 0, 64); // Clear the data first
memcpy(instrument, _sfxData + 20 + i * 30, 12);
instrument[63] = '\0';
diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp
index e4fd334926..ffc36b4b1a 100644
--- a/engines/cine/texte.cpp
+++ b/engines/cine/texte.cpp
@@ -29,70 +29,59 @@
namespace Cine {
-byte *textDataPtr;
-
const char **failureMessages;
const CommandeType *defaultActionCommand;
const CommandeType *systemMenu;
const CommandeType *confirmMenu;
const char **otherMessages;
-const char *commandPrepositionOn;
+const char *defaultCommandPreposition;
+const char **commandPrepositionTable;
void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency);
-void loadTextData(const char *pFileName, byte *pDestinationBuffer) {
- Common::File pFileHandle;
- uint16 entrySize;
- uint16 numEntry;
- uint16 i;
- byte *tempBuffer;
- uint16 dataSize;
-
- assert(pFileName);
- assert(pDestinationBuffer);
-
- if (!pFileHandle.open(pFileName))
- error("loadTextData(): Cannot open file %s", pFileName);
-
- entrySize = pFileHandle.readUint16BE();
- numEntry = pFileHandle.readUint16BE();
-
- dataSize = numEntry * entrySize;
- pFileHandle.read(pDestinationBuffer, numEntry * entrySize);
+/*! \brief Loads font data from the given file.
+ * The number of characters used in the font varies between game versions:
+ * 78 (Most PC, Amiga and Atari ST versions of Future Wars, but also Operation Stealth's Amiga demo),
+ * 85 (All observed versions of German Future Wars (Amiga and PC), possibly Spanish Future Wars too),
+ * 90 (Most PC, Amiga and Atari ST versions of Operation Stealth),
+ * 93 (All observed versions of German Operation Stealth (Amiga and PC)).
+ */
+void loadTextData(const char *filename) {
+ Common::File fileHandle;
+ assert(filename);
+
+ if (!fileHandle.open(filename))
+ error("loadTextData(): Cannot open file %s", filename);
+
+ static const uint headerSize = 2 + 2; // The entry size (16-bit) and entry count (16-bit).
+ const uint entrySize = fileHandle.readUint16BE(); // Observed values: 8.
+ const uint entryCount = fileHandle.readUint16BE(); // Observed values: 624, 680, 720, 744.
+ const uint fontDataSize = entryCount * entrySize; // Observed values: 4992, 5440, 5760, 5952.
+ const uint numChars = entryCount / entrySize; // Observed values: 78, 85, 90, 93.
+ const uint bytesPerChar = fontDataSize / numChars; // Observed values: 64.
+ static const uint bytesPerRow = FONT_WIDTH / 2; // The input font data is 4-bit so it takes only half the space
+
+ if (headerSize + fontDataSize != (uint)fileHandle.size()) {
+ warning("loadTextData: file '%s' (entrySize = %d, entryCount = %d) is of incorrect size %d", filename, entrySize, entryCount, fileHandle.size());
+ }
- tempBuffer = pDestinationBuffer;
+ Common::Array<byte> source;
+ source.resize(fontDataSize);
+ fileHandle.read(source.begin(), fontDataSize);
if (g_cine->getGameType() == Cine::GType_FW) {
- int numCharacters;
- if (g_cine->getFeatures() & GF_ALT_FONT) {
- numCharacters = 85;
- } else {
- numCharacters = 78;
- }
-
- dataSize = dataSize / numCharacters;
-
- loadRelatedPalette(pFileName);
+ loadRelatedPalette(filename);
+ }
- for (i = 0; i < numCharacters; i++) {
- gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8);
- generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0);
- tempBuffer += dataSize;
- }
- } else {
- for (i = 0; i < 90; i++) {
- gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8);
- generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0);
- tempBuffer += 0x40;
- }
+ for (uint i = 0; i < numChars; i++) {
+ gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][FONT_DATA], &source[i * bytesPerChar], bytesPerRow, FONT_HEIGHT);
+ generateMask(g_cine->_textHandler.textTable[i][FONT_DATA], g_cine->_textHandler.textTable[i][FONT_MASK], FONT_WIDTH * FONT_HEIGHT, 0);
}
- pFileHandle.close();
+ fileHandle.close();
}
-const CharacterEntry *fontParamTable;
-
-const CharacterEntry fontParamTable_standard[256] = {
+static const CharacterEntry fontParamTable_standard[NUM_FONT_CHARS] = {
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
@@ -129,7 +118,7 @@ const CharacterEntry fontParamTable_standard[256] = {
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}
};
-const CharacterEntry fontParamTable_alt[256] = {
+static const CharacterEntry fontParamTable_alt[NUM_FONT_CHARS] = {
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
@@ -208,6 +197,16 @@ void initLanguage(Common::Language lang) {
"NOACTION"
};
+ static const char *commandPrepositionTable_EN[] = {
+ "", // EXAMINE
+ "", // TAKE
+ "", // INVENTORY
+ "on", // USE
+ "", // OPERATE
+ "to", // SPEAK
+ "" // NOACTION
+ };
+
static const CommandeType systemMenu_EN[] = {
"Pause",
"Restart Game",
@@ -223,9 +222,8 @@ void initLanguage(Common::Language lang) {
"PAUSE",
"Loading | %s",
"Loading canceled ...",
- "No baclup in the drive...",
- "Please enter the backup name",
- "on"
+ "No backup in the drive...",
+ "Please enter the backup name"
};
static const CommandeType confirmMenu_EN[] = {
@@ -276,6 +274,16 @@ void initLanguage(Common::Language lang) {
"NOACTION"
};
+ static const char *commandPrepositionTable_FR[] = {
+ "", // EXAMINER
+ "", // PRENDRE
+ "", // INVENTAIRE
+ "sur", // UTILISER
+ "", // ACTIONNER
+ "a", // PARLER
+ "" // NOACTION
+ };
+
static const CommandeType systemMenu_FR[] = {
"Pause",
"Nouvelle partie",
@@ -297,8 +305,7 @@ void initLanguage(Common::Language lang) {
"Sauvegarde de | %s",
"Sauvegarde Annul\x82""e ...",
"Aucune sauvegarde dans le lecteur ...",
- "Veuillez entrer le Nom de la Sauvegarde .",
- "sur"
+ "Veuillez entrer le Nom de la Sauvegarde ."
};
static const char *failureMessages_ES[] = {
@@ -344,6 +351,16 @@ void initLanguage(Common::Language lang) {
"NOACTION"
};
+ static const char *commandPrepositionTable_ES[] = {
+ "", // EXAMINAR
+ "", // COGER
+ "", // INVENTARIO
+ "donde", // USAR
+ "", // ACCIONAR
+ "a", // HABLAR
+ "" // NOACTION
+ };
+
static const CommandeType systemMenu_ES[] = {
"Pause",
"Nueva partida",
@@ -365,8 +382,7 @@ void initLanguage(Common::Language lang) {
"Gabacion de| %s",
"Rrabacion anulada",
"No hay partidas grabadas en este disco...",
- "Teclea el nombre de la partida grabada",
- "donde"
+ "Teclea el nombre de la partida grabada"
};
static const char *failureMessages_DE[] = {
@@ -403,15 +419,25 @@ void initLanguage(Common::Language lang) {
};
static const CommandeType defaultActionCommand_DE[] = {
- "Pr\x81""fe",
+ "Pr\x81""fe", // FIXME? The third letter should be Latin Small Letter U with diaeresis
"Nimm",
"Bestand",
"Benutze",
- "Bet\x84tige",
+ "Bet\x84tige", // FIXME? The fourth letter should be Latin Small Letter A with diaeresis
"Sprich",
"NOACTION"
};
+ static const char *commandPrepositionTable_DE[] = {
+ "", // Prufe
+ "", // Nimm
+ "", // Bestand
+ "gegen", // Benutze
+ "", // Betatige
+ "a", // Sprich
+ "" // NOACTION
+ };
+
static const CommandeType systemMenu_DE[] = {
"Pause",
"Spiel Neu Starten",
@@ -433,8 +459,7 @@ void initLanguage(Common::Language lang) {
"Er L\x84""dt | %s",
"Ladevorgang Abgebrochen...",
"Kein Backup im Laufwerk...",
- "Geben Sie den Namen|der Sicherungsdiskette ein",
- "gegen"
+ "Geben Sie den Namen|der Sicherungsdiskette ein"
};
static const char *failureMessages_IT[] = {
@@ -480,6 +505,16 @@ void initLanguage(Common::Language lang) {
"NOACTION"
};
+ static const char *commandPrepositionTable_IT[] = {
+ "", // ESAMINARE
+ "", // PRENDERE
+ "", // INVENTARIO
+ "su", // UTILIZZARE
+ "", // AZIONARE
+ "a", // PARLARE
+ "" // NOACTION
+ };
+
static const CommandeType systemMenu_IT[] = {
"Pausa",
"Parte nuova",
@@ -501,8 +536,7 @@ void initLanguage(Common::Language lang) {
"Caricamento di| %s",
"Caricamento annullato...",
"Nessun salvataggio su questo disco...",
- "Vogliate accedere con il nome del salvataggio",
- "su"
+ "Vogliate accedere con il nome del salvataggio"
};
switch (lang) {
@@ -512,7 +546,8 @@ void initLanguage(Common::Language lang) {
systemMenu = systemMenu_FR;
confirmMenu = confirmMenu_FR;
otherMessages = otherMessages_FR;
- commandPrepositionOn = otherMessages_FR[7];
+ defaultCommandPreposition = commandPrepositionTable_FR[3];
+ commandPrepositionTable = commandPrepositionTable_FR;
break;
case Common::ES_ESP:
@@ -521,7 +556,8 @@ void initLanguage(Common::Language lang) {
systemMenu = systemMenu_ES;
confirmMenu = confirmMenu_ES;
otherMessages = otherMessages_ES;
- commandPrepositionOn = otherMessages_ES[7];
+ defaultCommandPreposition = commandPrepositionTable_ES[3];
+ commandPrepositionTable = commandPrepositionTable_ES;
break;
case Common::DE_DEU:
@@ -530,7 +566,8 @@ void initLanguage(Common::Language lang) {
systemMenu = systemMenu_DE;
confirmMenu = confirmMenu_DE;
otherMessages = otherMessages_DE;
- commandPrepositionOn = otherMessages_DE[7];
+ defaultCommandPreposition = commandPrepositionTable_DE[3];
+ commandPrepositionTable = commandPrepositionTable_DE;
break;
case Common::IT_ITA:
@@ -539,7 +576,8 @@ void initLanguage(Common::Language lang) {
systemMenu = systemMenu_IT;
confirmMenu = confirmMenu_IT;
otherMessages = otherMessages_IT;
- commandPrepositionOn = otherMessages_IT[7];
+ defaultCommandPreposition = commandPrepositionTable_IT[3];
+ commandPrepositionTable = commandPrepositionTable_IT;
break;
default:
@@ -548,14 +586,17 @@ void initLanguage(Common::Language lang) {
systemMenu = systemMenu_EN;
confirmMenu = confirmMenu_EN;
otherMessages = otherMessages_EN;
- commandPrepositionOn = otherMessages_EN[7];
+ defaultCommandPreposition = commandPrepositionTable_EN[3];
+ commandPrepositionTable = commandPrepositionTable_EN;
break;
}
if (g_cine->getFeatures() & GF_ALT_FONT) {
- fontParamTable = fontParamTable_alt;
+ // Copy alternative font parameter table to the current font parameter table
+ Common::copy(fontParamTable_alt, fontParamTable_alt + NUM_FONT_CHARS, g_cine->_textHandler.fontParamTable);
} else {
- fontParamTable = fontParamTable_standard;
+ // Copy standard font parameter to the current font parameter table
+ Common::copy(fontParamTable_standard, fontParamTable_standard + NUM_FONT_CHARS, g_cine->_textHandler.fontParamTable);
}
}
@@ -590,25 +631,16 @@ void loadPoldatDat(const char *fname) {
in.open(fname);
if (in.isOpen()) {
- CharacterEntry *ptr = (CharacterEntry *)malloc(sizeof(CharacterEntry) * 256);
-
- for (int i = 0; i < 256; i++) {
- ptr[i].characterIdx = (int)in.readByte();
- ptr[i].characterWidth = (int)in.readByte();
+ for (int i = 0; i < NUM_FONT_CHARS; i++) {
+ g_cine->_textHandler.fontParamTable[i].characterIdx = in.readByte();
+ g_cine->_textHandler.fontParamTable[i].characterWidth = in.readByte();
}
- fontParamTable = ptr;
-
in.close();
} else {
error("Cannot open file %s for reading", fname);
}
}
-void freePoldatDat() {
- free(const_cast<Cine::CharacterEntry *>(fontParamTable));
- fontParamTable = 0;
-}
-
/*! \brief Fit a substring of text into one line of fixed width text box
* \param str Text to fit
* \param maxWidth Text box width
@@ -633,7 +665,7 @@ int fitLine(const char *str, int maxWidth, int &words, int &width) {
bkpWidth = width;
bkpLen = i + 1;
} else {
- charWidth = fontParamTable[(unsigned char)str[i]].characterWidth + 1;
+ charWidth = g_cine->_textHandler.fontParamTable[(unsigned char)str[i]].characterWidth + 1;
width += charWidth;
}
diff --git a/engines/cine/texte.h b/engines/cine/texte.h
index f471c3c49e..0b1fc88e86 100644
--- a/engines/cine/texte.h
+++ b/engines/cine/texte.h
@@ -33,10 +33,24 @@ namespace Cine {
typedef char CommandeType[20];
-extern byte *textDataPtr;
+// Number of characters in a font
+#define NUM_FONT_CHARS 256
+
+#define FONT_WIDTH 16
+#define FONT_HEIGHT 8
+
+// Used for choosing between font's data and font's mask
+#define FONT_DATA 0
+#define FONT_MASK 1
+
+struct CharacterEntry {
+ byte characterIdx;
+ byte characterWidth;
+};
struct TextHandler {
- byte textTable[256][2][16 * 8];
+ byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH * FONT_HEIGHT];
+ CharacterEntry fontParamTable[NUM_FONT_CHARS];
};
extern const char **failureMessages;
@@ -44,20 +58,13 @@ extern const CommandeType *defaultActionCommand;
extern const CommandeType *systemMenu;
extern const CommandeType *confirmMenu;
extern const char **otherMessages;
-extern const char *commandPrepositionOn;
-
-struct CharacterEntry {
- byte characterIdx;
- byte characterWidth;
-};
-
-extern const CharacterEntry *fontParamTable;
+extern const char *defaultCommandPreposition;
+extern const char **commandPrepositionTable;
-void loadTextData(const char *pFileName, byte *pDestinationBuffer);
+void loadTextData(const char *filename);
void loadErrmessDat(const char *fname);
void freeErrmessDat(void);
void loadPoldatDat(const char *fname);
-void freePoldatDat(void);
int fitLine(const char *ptr, int maxWidth, int &words, int &width);
diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp
index 5d85ff6cab..7915fd1cf8 100644
--- a/engines/cine/unpack.cpp
+++ b/engines/cine/unpack.cpp
@@ -100,6 +100,14 @@ bool CineUnpacker::unpack(const byte *src, uint srcLen, byte *dst, uint dstLen)
_dstBegin = dst;
_dstEnd = dst + dstLen;
+ // Handle already unpacked data here
+ if (srcLen == dstLen) {
+ // Source length is same as destination length so the source
+ // data is already unpacked. Let's just copy it then.
+ memcpy(dst, src, srcLen);
+ return true;
+ }
+
// Initialize other variables
_src = _srcBegin + srcLen - 4;
uint32 unpackedLength = readSource(); // Unpacked length in bytes
diff --git a/engines/cine/unpack.h b/engines/cine/unpack.h
index e16cb594a9..2355df5ee1 100644
--- a/engines/cine/unpack.h
+++ b/engines/cine/unpack.h
@@ -35,14 +35,14 @@ namespace Cine {
* A LZ77 style decompressor for Delphine's data files
* used in at least Future Wars and Operation Stealth.
* @note Works backwards in the source and destination buffers.
- * @note Can work with source and destination in the same buffer if there's space.
+ * @warning Having the source and destination in the same buffer when unpacking can cause errors!
*/
class CineUnpacker {
public:
/**
* Unpacks packed data from the source buffer to the destination buffer.
- * @warning Do NOT call this on data that is not packed.
- * @note Source and destination buffer pointers can be the same as long as there's space for the unpacked data.
+ * @note You may call this on already unpacked data but then source length must be equal to destination length.
+ * @warning The source and destination should not point to the same buffer. If they do, errors may occur!
* @param src Pointer to the source buffer.
* @param srcLen Length of the source buffer.
* @param dst Pointer to the destination buffer.
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index 2fcb015fcd..92fd35d865 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -25,7 +25,6 @@
#include "common/endian.h"
-#include "common/events.h"
#include "common/savefile.h"
#include "cine/cine.h"
@@ -78,7 +77,7 @@ byte _danKeysPressed;
int16 playerCommand;
-char commandBuffer[80];
+Common::String commandBuffer;
char currentPrcName[20];
char currentRelName[20];
char currentObjectName[20];
@@ -95,11 +94,23 @@ int16 saveVar2;
byte isInPause = 0;
-// TODO: Implement inputVar0's changes in the program
-// Currently inputVar0 isn't updated anywhere even though it's used at least in processSeqListElement.
-uint16 inputVar0 = 0;
-byte inputVar1 = 0;
-uint16 inputVar2 = 0, inputVar3 = 0;
+/*! \brief Values used by the xMoveKeyb variable */
+enum xMoveKeybEnums {
+ kKeybMoveCenterX = 0,
+ kKeybMoveRight = 1,
+ kKeybMoveLeft = 2
+};
+
+/*! \brief Values used by the yMoveKeyb variable */
+enum yMoveKeybEnums {
+ kKeybMoveCenterY = 0,
+ kKeybMoveDown = 1,
+ kKeybMoveUp = 2
+};
+
+uint16 xMoveKeyb = kKeybMoveCenterX;
+bool egoMovedWithKeyboard = false;
+uint16 yMoveKeyb = kKeybMoveCenterY;
SelectedObjStruct currentSelectedObject;
@@ -113,10 +124,34 @@ static const int16 canUseOnItemTable[] = { 1, 0, 0, 1, 1, 0, 0 };
CommandeType objectListCommand[20];
int16 objListTab[20];
-uint16 exitEngine;
-uint16 zoneData[NUM_MAX_ZONE];
-uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth
+Common::Array<uint16> zoneData;
+Common::Array<uint16> zoneQuery; //!< Only exists in Operation Stealth
+
+/*! \brief Move the player character using the keyboard
+ * \param x Negative values move left, positive right, zero not at all
+ * \param y Negative values move down, positive up, zero not at all
+ * NOTE: If both x and y are zero then the character stops
+ * FIXME: This seems to only work in Operation Stealth. May need code changes somewhere else...
+ */
+void moveUsingKeyboard(int x, int y) {
+ if (x > 0) {
+ xMoveKeyb = kKeybMoveRight;
+ } else if (x < 0) {
+ xMoveKeyb = kKeybMoveLeft;
+ } else {
+ xMoveKeyb = kKeybMoveCenterX;
+ }
+
+ if (y > 0) {
+ yMoveKeyb = kKeybMoveUp;
+ } else if (y < 0) {
+ yMoveKeyb = kKeybMoveDown;
+ } else {
+ yMoveKeyb = kKeybMoveCenterY;
+ }
+ egoMovedWithKeyboard = x || y;
+}
void stopMusicAfterFadeOut(void) {
// if (g_sfxPlayer->_fadeOutCounter != 0 && g_sfxPlayer->_fadeOutCounter < 100) {
@@ -141,7 +176,6 @@ void addPlayerCommandMessage(int16 cmd) {
tmp.type = 3;
overlayList.push_back(tmp);
- waitForPlayerClick = 1;
}
int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) {
@@ -189,6 +223,15 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) {
frame = ABS((int16)(objectTable[it->objIdx].frame));
part = objectTable[it->objIdx].part;
+ // Additional case for negative frame values in Operation Stealth
+ if (g_cine->getGameType() == Cine::GType_OS && objectTable[it->objIdx].frame < 0) {
+ if ((it->type == 1) && (x >= objX) && (objX + frame >= x) && (y >= objY) && (objY + part >= y)) {
+ return it->objIdx;
+ } else {
+ continue;
+ }
+ }
+
if (it->type == 0) {
threshold = animDataTable[frame]._var1;
} else {
@@ -201,16 +244,19 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) {
xdif = x - objX;
ydif = y - objY;
- if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif < 0) || (ydif >= height) || !animDataTable[frame].data()) {
+ if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif <= 0) || (ydif >= height) || !animDataTable[frame].data()) {
continue;
}
if (g_cine->getGameType() == Cine::GType_OS) {
+ // This test isn't present in Operation Stealth's PC version's disassembly
+ // but removing it makes things crash sometimes (e.g. when selecting a verb
+ // and moving the mouse cursor around the floor in the airport's bathroom).
if (xdif >= width) {
continue;
}
- if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != part) {
+ if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != (part & 0x0F)) {
return it->objIdx;
} else if (it->type == 1 && gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) {
return it->objIdx;
@@ -270,6 +316,18 @@ void saveCommandVariables(Common::OutSaveFile &out) {
}
}
+/*! \brief Save the 80 bytes long command buffer padded to that length with zeroes. */
+void saveCommandBuffer(Common::OutSaveFile &out) {
+ // Let's make sure there's space for the trailing zero
+ // (That's why we subtract one from the maximum command buffer size here).
+ uint32 size = MIN<uint32>(commandBuffer.size(), kMaxCommandBufferSize - 1);
+ out.write(commandBuffer.c_str(), size);
+ // Write the rest as zeroes (Here we also write the string's trailing zero)
+ for (uint i = 0; i < kMaxCommandBufferSize - size; i++) {
+ out.writeByte(0);
+ }
+}
+
void saveAnimDataTable(Common::OutSaveFile &out) {
out.writeUint16BE(NUM_MAX_ANIMDATA); // Entry count
out.writeUint16BE(0x1E); // Entry size
@@ -439,7 +497,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle
uint animEntrySize = animEntrySizeChoices[i];
// Jump over the animDataTable entries and the screen parameters
- uint32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams;
+ int32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams;
// Check that there's data left after the point we're going to jump to
if (newPos >= fHandle.size()) {
continue;
@@ -570,16 +628,7 @@ void CineEngine::resetEngine() {
relTable.clear();
scriptTable.clear();
messageTable.clear();
-
- for (int i = 0; i < NUM_MAX_OBJECT; i++) {
- objectTable[i].x = 0;
- objectTable[i].y = 0;
- objectTable[i].part = 0;
- objectTable[i].name[0] = 0;
- objectTable[i].frame = 0;
- objectTable[i].mask = 0;
- objectTable[i].costume = 0;
- }
+ resetObjectTable();
globalVars.reset();
@@ -596,7 +645,7 @@ void CineEngine::resetEngine() {
playerCommand = -1;
isDrawCommandEnabled = 0;
- strcpy(commandBuffer, "");
+ commandBuffer = "";
globalVars[VAR_MOUSE_X_POS] = 0;
globalVars[VAR_MOUSE_Y_POS] = 0;
@@ -797,7 +846,10 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) {
globalVars.load(in, NUM_MAX_VAR);
loadZoneData(in);
loadCommandVariables(in);
- in.read(commandBuffer, 0x50);
+ char tempCommandBuffer[kMaxCommandBufferSize];
+ in.read(tempCommandBuffer, kMaxCommandBufferSize);
+ commandBuffer = tempCommandBuffer;
+ renderer->setCommand(commandBuffer);
loadZoneQuery(in);
// TODO: Use the loaded string (Current music name (String, 13 bytes)).
@@ -934,7 +986,9 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor
loadCommandVariables(in);
// At 0x22A9 (i.e. 0x22A1 + 4 * 2):
- in.read(commandBuffer, 0x50);
+ char tempCommandBuffer[kMaxCommandBufferSize];
+ in.read(tempCommandBuffer, kMaxCommandBufferSize);
+ commandBuffer = tempCommandBuffer;
renderer->setCommand(commandBuffer);
// At 0x22F9 (i.e. 0x22A9 + 0x50):
@@ -1038,7 +1092,7 @@ bool CineEngine::makeLoad(char *saveName) {
// that's not implemented here because it was never used in a stable
// release of ScummVM but only during development (From revision 31453,
// which introduced the problem, until revision 32073, which fixed it).
- // Therefore be bail out if we detect this particular savegame format.
+ // Therefore we bail out if we detect this particular savegame format.
warning("Detected a known broken savegame format, not loading savegame");
load = false; // Don't load the savegame
} else if (saveGameFormat == ANIMSIZE_UNKNOWN) {
@@ -1082,7 +1136,7 @@ void CineEngine::makeSaveFW(Common::OutSaveFile &out) {
globalVars.save(out, NUM_MAX_VAR);
saveZoneData(out);
saveCommandVariables(out);
- out.write(commandBuffer, 0x50);
+ saveCommandBuffer(out);
out.writeUint16BE(renderer->_cmdY);
out.writeUint16BE(bgVar0);
@@ -1167,7 +1221,7 @@ void CineEngine::makeSystemMenu(void) {
{
getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
- exitEngine = 1;
+ quitGame();
}
break;
}
@@ -1297,7 +1351,7 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) {
globalVars.save(out, NUM_MAX_VAR);
saveZoneData(out);
saveCommandVariables(out);
- out.write(commandBuffer, 0x50);
+ saveCommandBuffer(out);
saveZoneQuery(out);
// FIXME: Save a proper name here, saving an empty string currently.
@@ -1360,19 +1414,38 @@ void drawDoubleMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 c
}
void processInventory(int16 x, int16 y) {
- int16 listSize = buildObjectListCommand(-2);
uint16 button;
+ int menuWidth;
+ int listSize;
+ int commandParam;
+
+ if (g_cine->getGameType() == Cine::GType_FW) {
+ menuWidth = 140;
+ commandParam = -2;
+ } else { // Operation Stealth
+ menuWidth = 160;
+ commandParam = -3;
+ }
+
+ listSize = buildObjectListCommand(commandParam);
if (!listSize)
return;
- renderer->drawMenu(objectListCommand, listSize, x, y, 140, -1);
+ renderer->drawMenu(objectListCommand, listSize, x, y, menuWidth, -1);
renderer->blit();
do {
manageEvents();
getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16);
} while (!button);
+
+ do {
+ manageEvents();
+ getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16);
+ } while (button);
+
+ // TODO: Both Future Wars and Operation Stealth call showMouse, drawMouse or something similar here.
}
int16 buildObjectListCommand(int16 param) {
@@ -1416,6 +1489,8 @@ int16 selectSubObject(int16 x, int16 y, int16 param) {
return objListTab[selectedObject];
}
+// TODO: Make separate functions for Future Wars's and Operation Stealth's version of this function, this is getting too messy
+// TODO: Add support for using the different prepositions for different verbs (Doesn't work currently)
void makeCommandLine(void) {
uint16 x, y;
@@ -1423,9 +1498,9 @@ void makeCommandLine(void) {
commandVar2 = -10;
if (playerCommand != -1) {
- strcpy(commandBuffer, defaultActionCommand[playerCommand]);
+ commandBuffer = defaultActionCommand[playerCommand];
} else {
- strcpy(commandBuffer, "");
+ commandBuffer = "";
}
if ((playerCommand != -1) && (choiceResultTable[playerCommand] == 2)) { // need object selection ?
@@ -1440,8 +1515,12 @@ void makeCommandLine(void) {
}
if (si < 0) {
- playerCommand = -1;
- strcpy(commandBuffer, "");
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ canUseOnObject = 0;
+ } else { // Future Wars
+ playerCommand = -1;
+ commandBuffer = "";
+ }
} else {
if (g_cine->getGameType() == Cine::GType_OS) {
if (si >= 8000) {
@@ -1454,23 +1533,28 @@ void makeCommandLine(void) {
commandVar3[0] = si;
commandVar1 = 1;
-
- strcat(commandBuffer, " ");
- strcat(commandBuffer, objectTable[commandVar3[0]].name);
- strcat(commandBuffer, " ");
- strcat(commandBuffer, commandPrepositionOn);
+ commandBuffer += " ";
+ commandBuffer += objectTable[commandVar3[0]].name;
+ commandBuffer += " ";
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ commandBuffer += commandPrepositionTable[playerCommand];
+ } else { // Future Wars
+ commandBuffer += defaultCommandPreposition;
+ }
}
- } else {
+ }
+
+ if (g_cine->getGameType() == Cine::GType_OS || !(playerCommand != -1 && choiceResultTable[playerCommand] == 2)) {
if (playerCommand == 2) {
getMouseData(mouseUpdateStatus, &dummyU16, &x, &y);
processInventory(x, y + 8);
playerCommand = -1;
commandVar1 = 0;
- strcpy(commandBuffer, "");
+ commandBuffer = "";
}
}
- if (g_cine->getGameType() == Cine::GType_OS) {
+ if (g_cine->getGameType() == Cine::GType_OS && playerCommand != 2) {
if (playerCommand != -1 && canUseOnObject != 0) { // call use on sub object
int16 si;
@@ -1478,34 +1562,38 @@ void makeCommandLine(void) {
si = selectSubObject(x, y + 8, -subObjectUseTable[playerCommand]);
- if (si) {
+ if (si >= 0) {
if (si >= 8000) {
si -= 8000;
}
commandVar3[commandVar1] = si;
-
commandVar1++;
-
- // TODO: add command message draw
+ commandBuffer += " ";
+ commandBuffer += objectTable[si].name;
}
+ }
- isDrawCommandEnabled = 1;
+ isDrawCommandEnabled = 1;
- if (playerCommand != -1 && choiceResultTable[playerCommand] == commandVar1) {
- SelectedObjStruct obj;
- obj.idx = commandVar3[0];
- obj.param = commandVar3[1];
- int16 di = getRelEntryForObject(playerCommand, commandVar1, &obj);
+ if (playerCommand != -1 && choiceResultTable[playerCommand] == commandVar1) {
+ SelectedObjStruct obj;
+ obj.idx = commandVar3[0];
+ obj.param = commandVar3[1];
+ int16 di = getRelEntryForObject(playerCommand, commandVar1, &obj);
- if (di != -1) {
- runObjectScript(di);
- }
- }
+ if (di != -1) {
+ runObjectScript(di);
+ } // TODO: else addFailureMessage(playerCommand)
+
+ playerCommand = -1;
+ commandVar1 = 0;
+ commandBuffer = "";
}
}
- if (!disableSystemMenu) {
+ if (g_cine->getGameType() == Cine::GType_OS || !disableSystemMenu) {
+ isDrawCommandEnabled = 1;
renderer->setCommand(commandBuffer);
}
}
@@ -1678,6 +1766,11 @@ uint16 executePlayerInput(void) {
}
if (allowPlayerInput) {
+ if (isDrawCommandEnabled) {
+ renderer->setCommand(commandBuffer);
+ isDrawCommandEnabled = 0;
+ }
+
getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
while (mouseButton && currentEntry < 200) {
@@ -1716,8 +1809,9 @@ uint16 executePlayerInput(void) {
commandVar3[commandVar1] = si;
commandVar1++;
- strcat(commandBuffer, " ");
- strcat(commandBuffer, objectTable[si].name);
+ commandBuffer += " ";
+ commandBuffer += objectTable[si].name;
+
isDrawCommandEnabled = 1;
@@ -1739,8 +1833,8 @@ uint16 executePlayerInput(void) {
playerCommand = -1;
commandVar1 = 0;
- strcpy(commandBuffer, "");
- renderer->setCommand("");
+ commandBuffer = "";
+ renderer->setCommand(commandBuffer);
}
} else {
globalVars[VAR_MOUSE_X_POS] = mouseX;
@@ -1761,13 +1855,7 @@ uint16 executePlayerInput(void) {
if (commandVar2 != objIdx) {
if (objIdx != -1) {
- char command[256];
-
- strcpy(command, commandBuffer);
- strcat(command, " ");
- strcat(command, objectTable[objIdx].name);
-
- renderer->setCommand(command);
+ renderer->setCommand(commandBuffer + " " + objectTable[objIdx].name);
} else {
isDrawCommandEnabled = 1;
}
@@ -1858,8 +1946,8 @@ uint16 executePlayerInput(void) {
var_2 = 0;
}
- if (inputVar1 && allowPlayerInput) { // use keyboard
- inputVar1 = 0;
+ if (egoMovedWithKeyboard && allowPlayerInput) { // use keyboard
+ egoMovedWithKeyboard = false;
switch (globalVars[VAR_MOUSE_X_MODE]) {
case 1:
@@ -1891,8 +1979,8 @@ uint16 executePlayerInput(void) {
globalVars[VAR_MOUSE_X_POS] = mouseX;
globalVars[VAR_MOUSE_Y_POS] = mouseY;
} else {
- if (inputVar2) {
- if (inputVar2 == 2) {
+ if (xMoveKeyb) {
+ if (xMoveKeyb == kKeybMoveLeft) {
globalVars[VAR_MOUSE_X_POS] = 1;
} else {
globalVars[VAR_MOUSE_X_POS] = 320;
@@ -1901,8 +1989,8 @@ uint16 executePlayerInput(void) {
globalVars[VAR_MOUSE_X_POS] = mouseX;
}
- if (inputVar3) {
- if (inputVar3 == 2) {
+ if (yMoveKeyb) {
+ if (yMoveKeyb == kKeybMoveUp) {
globalVars[VAR_MOUSE_Y_POS] = 1;
} else {
globalVars[VAR_MOUSE_Y_POS] = 200;
@@ -1943,6 +2031,14 @@ uint16 executePlayerInput(void) {
}
}
+ // Update Operation Stealth specific global variables.
+ // This fixes swimming at the bottom of the ocean after
+ // having been thrown into it with the girl.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ globalVars[251] = globalVars[VAR_MOUSE_X_POS];
+ globalVars[252] = globalVars[VAR_MOUSE_Y_POS];
+ }
+
return var_5E;
}
@@ -1984,9 +2080,22 @@ void drawSprite(Common::List<overlay>::iterator it, const byte *spritePtr, const
void removeMessages() {
Common::List<overlay>::iterator it;
+ bool remove;
for (it = overlayList.begin(); it != overlayList.end(); ) {
- if (it->type == 2 || it->type == 3) {
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ // NOTE: These are really removeOverlay calls that have been deferred.
+ // In Operation Stealth's disassembly elements are removed from the
+ // overlay list right in the drawOverlays function (And actually in
+ // some other places too) and that's where incrementing a the overlay's
+ // last parameter by one if it's negative and testing it for positivity
+ // comes from too.
+ remove = it->type == 3 || (it->type == 2 && (it->color >= 0 || ++it->color >= 0));
+ } else { // Future Wars
+ remove = it->type == 2 || it->type == 3;
+ }
+
+ if (remove) {
it = overlayList.erase(it);
} else {
++it;
@@ -2069,7 +2178,6 @@ void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 par
tmp.color = param5;
overlayList.push_back(tmp);
- waitForPlayerClick = 1;
}
Common::List<SeqListElement> seqList;
@@ -2328,9 +2436,9 @@ void processSeqListElement(SeqListElement &element) {
}
computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2);
} else {
- if (inputVar0 && allowPlayerInput) {
+ if (xMoveKeyb && allowPlayerInput) {
int16 adder = param1 + 1;
- if (inputVar0 != 1) {
+ if (xMoveKeyb != kKeybMoveRight) {
adder = -adder;
}
// FIXME: In Operation Stealth's disassembly global variable 251 is used here
@@ -2339,9 +2447,9 @@ void processSeqListElement(SeqListElement &element) {
globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder;
}
- if (inputVar1 && allowPlayerInput) {
+ if (yMoveKeyb && allowPlayerInput) {
int16 adder = param2 + 1;
- if (inputVar1 != 1) {
+ if (yMoveKeyb != kKeybMoveDown) {
adder = -adder;
}
// TODO: Name currently unnamed global variable 252
diff --git a/engines/cine/various.h b/engines/cine/various.h
index d87679ca08..b841908c65 100644
--- a/engines/cine/various.h
+++ b/engines/cine/various.h
@@ -33,6 +33,9 @@
namespace Cine {
+// Maximum size of the command buffer including the trailing zero
+#define kMaxCommandBufferSize 80
+
void initLanguage(Common::Language lang);
int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false);
@@ -85,7 +88,7 @@ extern byte _danKeysPressed;
extern int16 playerCommand;
-extern char commandBuffer[80];
+extern Common::String commandBuffer;
extern char currentPrcName[20];
extern char currentRelName[20];
@@ -117,8 +120,6 @@ void mainLoopSub6(void);
void checkForPendingDataLoad(void);
-extern uint16 exitEngine;
-
void hideMouse(void);
void removeExtention(char *dest, const char *source);
@@ -129,8 +130,8 @@ struct SelectedObjStruct {
};
#define NUM_MAX_ZONE 16
-extern uint16 zoneData[NUM_MAX_ZONE];
-extern uint16 zoneQuery[NUM_MAX_ZONE];
+extern Common::Array<uint16> zoneData;
+extern Common::Array<uint16> zoneQuery;
void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5);
@@ -145,6 +146,7 @@ void processSeqList(void);
void resetGfxEntityEntry(uint16 objIdx);
bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y);
+void moveUsingKeyboard(int x, int y);
} // End of namespace Cine
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index 5d16c6e68a..7064f81a90 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -243,7 +243,7 @@ ovlData3Struct *scriptFunc1Sub2(int32 scriptNumber, int32 param) {
return NULL;
}
- return ((ovlData3Struct *) (ovlData->ptr1 + param * 0x1C));
+ return &ovlData->ptr1[param];
}
void scriptFunc2(int scriptNumber, scriptInstanceStruct * scriptHandle,
diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp
index 6c7be713ef..b45b6dc866 100644
--- a/engines/cruise/ctp.cpp
+++ b/engines/cruise/ctp.cpp
@@ -153,8 +153,8 @@ void makeCtStruct(uint8* str, int16 table[][40], int num, int z) {
int16* a2;
a1 = a2 = (int16*)str;
- a2 += 4+sizeof(int16*); // skip header
-
+ a2 += sizeof(int16*) / sizeof(int16) + 6; // skip header
+
int16* XArray = XMIN_XMAX;
int minY = *XArray++;
@@ -178,8 +178,8 @@ void makeCtStruct(uint8* str, int16 table[][40], int num, int z) {
adrStructPoly = (uint8*)a2;
- *(uint16**)a2 = (uint16*)-1;
-
+ *(uint16**)a2 = (uint16*)-1; //chained list terminator
+
a1+=sizeof(int16*);
*a1++=num;
*a1++=walkboxColor[num];
@@ -339,20 +339,20 @@ int initCt(const char *ctpName) {
makeCtStruct(adrStructPoly, ctp_walkboxTable, i, 0 );
}
- polyStructExp = adrStructPoly += 4;
+ polyStructExp = adrStructPoly += sizeof(int16 *);
for(int i= numberOfWalkboxes-1; i >=0; i--) {
makeCtStruct(adrStructPoly, ctp_walkboxTable, i, walkboxZoom[i] * 20 );
}
- int ctSize = (adrStructPoly - ptr) + 4; // for now, the +4 is a safe zone
+ int ctSize = (adrStructPoly - ptr) + sizeof(int16 *); // for now, the +sizeof(int16 *) is a safe zone
adrStructPoly = polyStructNorm = polyStruct = (uint8 *) malloc(ctSize);
for(int i= numberOfWalkboxes-1; i >=0; i--) {
makeCtStruct(adrStructPoly, ctp_walkboxTable, i, 0);
}
- polyStructExp = adrStructPoly += 4;
+ polyStructExp = adrStructPoly += sizeof(int16 *);
for(int i= numberOfWalkboxes-1; i >=0; i--) {
makeCtStruct(adrStructPoly, ctp_walkboxTable, i, walkboxZoom[i] * 20);
diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp
index 7ce69448a6..c274291142 100644
--- a/engines/cruise/dataLoader.cpp
+++ b/engines/cruise/dataLoader.cpp
@@ -24,6 +24,7 @@
*/
#include "cruise/cruise_main.h"
+#include "common/endian.h"
namespace Cruise {
@@ -412,7 +413,6 @@ int loadFNTSub(uint8 *ptr, int destIdx) {
}
int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry) {
- uint8 *ptr2;
uint8 *ptr3;
int offset;
int sec = 0;
@@ -422,28 +422,27 @@ int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentD
sec = 1;
}
- ptr2 = ptr + 4;
-
- memcpy(&numIdx, ptr2, 2);
- flipShort(&numIdx);
+ numIdx = READ_BE_UINT16(ptr + 4);
ptr3 = ptr + 6;
offset = currentEntryIdx * 16;
{
- uint8 *ptr4;
int resourceSize;
int fileIndex;
setHeaderEntry localBuffer;
uint8 *ptr5;
- ptr4 = ptr + offset + 6;
-
- memcpy(&localBuffer, ptr4, sizeof(setHeaderEntry));
+ Common::MemoryReadStream s4(ptr + offset + 6, 16);
- flipLong((int32 *) & localBuffer.field_0);
- flipGen(&localBuffer.width, 12);
+ localBuffer.field_0 = s4.readUint32BE();
+ localBuffer.width = s4.readUint16BE();
+ localBuffer.height = s4.readUint16BE();
+ localBuffer.type = s4.readUint16BE();
+ localBuffer.transparency = s4.readUint16BE();
+ localBuffer.field_C = s4.readUint16BE();
+ localBuffer.field_E = s4.readUint16BE();
if (sec == 1) {
localBuffer.width = localBuffer.width - (localBuffer.type * 2); // Type 1: Width - (1*2) , Type 5: Width - (5*2)
diff --git a/engines/cruise/object.cpp b/engines/cruise/object.cpp
index 66a3a53018..bb8d85acd0 100644
--- a/engines/cruise/object.cpp
+++ b/engines/cruise/object.cpp
@@ -58,7 +58,7 @@ objDataStruct *getObjectDataFromOverlay(int ovlIdx, int objIdx) {
}
int16 getMultipleObjectParam(int16 overlayIdx, int16 objectIdx, objectParamsQuery *returnParam) {
- objectParams *ptr2;
+ objectParams *ptr2 = 0;
objDataStruct *ptr;
ovlDataStruct *ovlData;
// int16 type;
@@ -246,7 +246,7 @@ int16 getSingleObjectParam(int16 overlayIdx, int16 param2, int16 param3, int16 *
//char* ptr3 = NULL;
objDataStruct *ptr;
ovlDataStruct *ovlData;
- objectParams *ptr2;
+ objectParams *ptr2 = 0;
ptr = getObjectDataFromOverlay(overlayIdx, param2);
diff --git a/engines/cruise/overlay.cpp b/engines/cruise/overlay.cpp
index d3cb93c37c..4d476ceaf1 100644
--- a/engines/cruise/overlay.cpp
+++ b/engines/cruise/overlay.cpp
@@ -23,6 +23,8 @@
*
*/
+#include "common/stream.h"
+
#include "cruise/cruise_main.h"
namespace Cruise {
@@ -50,8 +52,7 @@ int loadOverlay(const char *scriptName) {
char fileName[50];
int fileIdx;
int unpackedSize;
- char *unpackedBuffer;
- char *scriptPtr;
+ byte *unpackedBuffer;
ovlDataStruct *ovlData;
printf("Load overlay: %s\n", scriptName);
@@ -105,7 +106,7 @@ int loadOverlay(const char *scriptName) {
unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2;
// TODO: here, can unpack in gfx module buffer
- unpackedBuffer = (char *)mallocAndZero(unpackedSize);
+ unpackedBuffer = (byte *)mallocAndZero(unpackedSize);
if (!unpackedBuffer) {
return (-2);
@@ -127,12 +128,13 @@ int loadOverlay(const char *scriptName) {
printf("OVL loading done...\n");
- scriptPtr = unpackedBuffer;
+ Common::MemoryReadStream s(unpackedBuffer, unpackedSize);
ovlData = overlayTable[scriptIdx].ovlData;
- memcpy(ovlData, scriptPtr, sizeof(ovlDataStruct));
-
+ // Skip pointers
+ s.skip(60);
+
ovlData->arrayProc = NULL;
ovlData->ptr1 = NULL;
ovlData->arrayObject = NULL;
@@ -148,24 +150,22 @@ int loadOverlay(const char *scriptName) {
ovlData->arrayNameSymbGlob = NULL;
ovlData->data4Ptr = NULL;
ovlData->ptr8 = NULL;
- ovlData->numProc = readB16(scriptPtr + 60);
- ovlData->numRel = readB16(scriptPtr + 62);
- ovlData->numSymbGlob = readB16(scriptPtr + 64);
- ovlData->numRelocGlob = readB16(scriptPtr + 66);
- ovlData->numMsgRelHeader = readB16(scriptPtr + 68);
- ovlData->numObj = readB16(scriptPtr + 70);
- ovlData->numStrings = readB16(scriptPtr + 72);
- ovlData->size8 = readB16(scriptPtr + 74);
- ovlData->size9 = readB16(scriptPtr + 76);
- ovlData->nameExportSize = readB16(scriptPtr + 78);
- ovlData->exportNamesSize = readB16(scriptPtr + 80);
- ovlData->specialString2Length = readB16(scriptPtr + 82);
- ovlData->sizeOfData4 = readB16(scriptPtr + 84);
- ovlData->size12 = readB16(scriptPtr + 86);
- ovlData->specialString1Length = readB16(scriptPtr + 88);
- ovlData->scriptNumber = readB16(scriptPtr + 90);
-
- scriptPtr += 92;
+ ovlData->numProc = s.readUint16BE();
+ ovlData->numRel = s.readUint16BE();
+ ovlData->numSymbGlob = s.readUint16BE();
+ ovlData->numRelocGlob = s.readUint16BE();
+ ovlData->numMsgRelHeader = s.readUint16BE();
+ ovlData->numObj = s.readUint16BE();
+ ovlData->numStrings = s.readUint16BE();
+ ovlData->size8 = s.readUint16BE();
+ ovlData->size9 = s.readUint16BE();
+ ovlData->nameExportSize = s.readUint16BE();
+ ovlData->exportNamesSize = s.readUint16BE();
+ ovlData->specialString2Length = s.readUint16BE();
+ ovlData->sizeOfData4 = s.readUint16BE();
+ ovlData->size12 = s.readUint16BE();
+ ovlData->specialString1Length = s.readUint16BE();
+ ovlData->scriptNumber = s.readUint16BE();
if (ovlData->numSymbGlob) { // export data
int i;
@@ -177,13 +177,11 @@ int loadOverlay(const char *scriptName) {
}
for (i = 0; i < ovlData->numSymbGlob; i++) {
- ovlData->arraySymbGlob[i].var0 = readB16(scriptPtr);
- ovlData->arraySymbGlob[i].var2 = readB16(scriptPtr + 2);
- ovlData->arraySymbGlob[i].var4 = readB16(scriptPtr + 4);
- ovlData->arraySymbGlob[i].idx = readB16(scriptPtr + 6);
- ovlData->arraySymbGlob[i].offsetToName = readB16(scriptPtr + 8);
-
- scriptPtr += 10;
+ ovlData->arraySymbGlob[i].var0 = s.readUint16BE();
+ ovlData->arraySymbGlob[i].var2 = s.readUint16BE();
+ ovlData->arraySymbGlob[i].var4 = s.readUint16BE();
+ ovlData->arraySymbGlob[i].idx = s.readUint16BE();
+ ovlData->arraySymbGlob[i].offsetToName = s.readUint16BE();
}
}
@@ -194,8 +192,7 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->arrayNameSymbGlob, scriptPtr, ovlData->exportNamesSize);
- scriptPtr += ovlData->exportNamesSize;
+ s.read(ovlData->arrayNameSymbGlob, ovlData->exportNamesSize);
}
if (ovlData->numRelocGlob) { // import data
@@ -210,13 +207,11 @@ int loadOverlay(const char *scriptName) {
}
for (i = 0; i < ovlData->numRelocGlob; i++) {
- ovlData->arrayRelocGlob[i].var0 = readB16(scriptPtr);
- ovlData->arrayRelocGlob[i].var1 = readB16(scriptPtr + 2);
- ovlData->arrayRelocGlob[i].linkType = readB16(scriptPtr + 4);
- ovlData->arrayRelocGlob[i].linkIdx = readB16(scriptPtr + 6);
- ovlData->arrayRelocGlob[i].nameOffset = readB16(scriptPtr + 8);
-
- scriptPtr += 10;
+ ovlData->arrayRelocGlob[i].var0 = s.readUint16BE();
+ ovlData->arrayRelocGlob[i].var1 = s.readUint16BE();
+ ovlData->arrayRelocGlob[i].linkType = s.readUint16BE();
+ ovlData->arrayRelocGlob[i].linkIdx = s.readUint16BE();
+ ovlData->arrayRelocGlob[i].nameOffset = s.readUint16BE();
}
}
@@ -226,13 +221,12 @@ int loadOverlay(const char *scriptName) {
if (!ovlData->arrayNameRelocGlob) {
return (-2);
}
-
- memcpy(ovlData->arrayNameRelocGlob, scriptPtr,
- ovlData->nameExportSize);
- scriptPtr += ovlData->nameExportSize;
+
+ s.read(ovlData->arrayNameRelocGlob, ovlData->nameExportSize);
}
if (ovlData->numMsgRelHeader) { // link data
+ int i;
ASSERT(sizeof(linkDataStruct) == 0x22);
ovlData->arrayMsgRelHeader = (linkDataStruct *) mallocAndZero(ovlData->numMsgRelHeader * sizeof(linkDataStruct));
@@ -241,9 +235,30 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->arrayMsgRelHeader, scriptPtr, ovlData->numMsgRelHeader * sizeof(linkDataStruct));
- scriptPtr += ovlData->numMsgRelHeader * sizeof(linkDataStruct);
- flipGen(ovlData->arrayMsgRelHeader, ovlData->numMsgRelHeader * sizeof(linkDataStruct));
+ for (i = 0; i < ovlData->numMsgRelHeader; i++) {
+ ovlData->arrayMsgRelHeader[i].type = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].id = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].offsetVerbeName = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].verbOverlay = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].verbNumber = s.readUint16BE();
+
+ ovlData->arrayMsgRelHeader[i].obj1Overlay = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].obj1Number = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].obj2Overlay = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].obj2Number = s.readUint16BE();
+
+ ovlData->arrayMsgRelHeader[i].trackX = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].trackY = s.readUint16BE();
+
+ ovlData->arrayMsgRelHeader[i].obj1NewState = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].obj2NewState = s.readUint16BE();
+
+ ovlData->arrayMsgRelHeader[i].obj1OldState = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].obj2OldState = s.readUint16BE();
+
+ ovlData->arrayMsgRelHeader[i].trackDirection = s.readUint16BE();
+ ovlData->arrayMsgRelHeader[i].dialog = s.readUint16BE();
+ }
}
if (ovlData->numProc) { // script
@@ -251,53 +266,47 @@ int loadOverlay(const char *scriptName) {
int i;
ovlData->arrayProc =
- (ovlData3Struct *) mallocAndZero(ovlData->numProc *
- sizeof(ovlData3Struct));
+ (ovlData3Struct *) mallocAndZero(ovlData->numProc * sizeof(ovlData3Struct));
if (!ovlData->arrayProc) {
-/* releaseScript(scriptIdx,scriptName);
-
- if (freeIsNeeded) {
- freePtr(unpackedBuffer);
- } */
-
return (-2);
}
- memcpy(ovlData->arrayProc, scriptPtr,
- ovlData->numProc * sizeof(ovlData3Struct));
- scriptPtr += ovlData->numProc * 0x1C;
-
- flipGen(ovlData->arrayProc,
- ovlData->numProc * sizeof(ovlData3Struct));
+ for (i = 0; i < ovlData->numProc; i++) {
+ s.skip(4);
+ ovlData->arrayProc[i].dataPtr = NULL;
+ ovlData->arrayProc[i].sizeOfData = s.readUint16BE();
+ ovlData->arrayProc[i].offsetToSubData3 = s.readUint16BE();
+ ovlData->arrayProc[i].offsetToImportData = s.readUint16BE();
+ ovlData->arrayProc[i].offsetToSubData2 = s.readUint16BE();
+ ovlData->arrayProc[i].offsetToImportName = s.readUint16BE();
+ ovlData->arrayProc[i].offsetToSubData5 = s.readUint16BE();
+ ovlData->arrayProc[i].sysKey = s.readUint16BE();
+ ovlData->arrayProc[i].var12 = s.readUint16BE();
+ ovlData->arrayProc[i].numRelocGlob = s.readUint16BE();
+ ovlData->arrayProc[i].subData2Size = s.readUint16BE();
+ ovlData->arrayProc[i].var18 = s.readUint16BE();
+ ovlData->arrayProc[i].var1A = s.readUint16BE();
+ }
tempPtr = ovlData->arrayProc;
for (i = 0; i < ovlData->numProc; i++) {
- uint8 *ptr = tempPtr->dataPtr =
- (uint8 *) mallocAndZero(tempPtr->sizeOfData);
-
- if (!ptr) {
- /* releaseScript(scriptIdx,scriptName);
- *
- * if (freeIsNeeded)
- * {
- * freePtr(unpackedBuffer);
- * } */
+ tempPtr->dataPtr = (uint8 *) mallocAndZero(tempPtr->sizeOfData);
+ if (!tempPtr->dataPtr) {
return (-2);
}
- memcpy(ptr, scriptPtr, tempPtr->sizeOfData);
- scriptPtr += tempPtr->sizeOfData;
+ s.read(tempPtr->dataPtr, tempPtr->sizeOfData);
if (tempPtr->offsetToImportData) {
- flipGen(ptr + tempPtr->offsetToImportData,
+ flipGen(tempPtr->dataPtr + tempPtr->offsetToImportData,
tempPtr->numRelocGlob * 10);
}
if (tempPtr->offsetToSubData2) {
- flipGen(ptr + tempPtr->offsetToImportData,
+ flipGen(tempPtr->dataPtr + tempPtr->offsetToSubData2,
tempPtr->subData2Size * 10);
}
@@ -310,43 +319,47 @@ int loadOverlay(const char *scriptName) {
int i;
ovlData->ptr1 =
- (uint8 *) mallocAndZero(ovlData->numRel * 0x1C);
+ (ovlData3Struct *) mallocAndZero(ovlData->numRel * sizeof(ovlData3Struct));
if (!ovlData->ptr1) {
return (-2);
}
- memcpy(ovlData->ptr1, scriptPtr, ovlData->numRel * 0x1C);
- scriptPtr += ovlData->numRel * 0x1C;
- flipGen(ovlData->ptr1, ovlData->numRel * 0x1C);
-
+ for (i = 0; i < ovlData->numRel; i++) {
+ s.skip(4);
+ ovlData->ptr1[i].dataPtr = NULL;
+ ovlData->ptr1[i].sizeOfData = s.readUint16BE();
+ ovlData->ptr1[i].offsetToSubData3 = s.readUint16BE();
+ ovlData->ptr1[i].offsetToImportData = s.readUint16BE();
+ ovlData->ptr1[i].offsetToSubData2 = s.readUint16BE();
+ ovlData->ptr1[i].offsetToImportName = s.readUint16BE();
+ ovlData->ptr1[i].offsetToSubData5 = s.readUint16BE();
+ ovlData->ptr1[i].sysKey = s.readUint16BE();
+ ovlData->ptr1[i].var12 = s.readUint16BE();
+ ovlData->ptr1[i].numRelocGlob = s.readUint16BE();
+ ovlData->ptr1[i].subData2Size = s.readUint16BE();
+ ovlData->ptr1[i].var18 = s.readUint16BE();
+ ovlData->ptr1[i].var1A = s.readUint16BE();
+ }
+
tempPtr = (ovlData3Struct *) ovlData->ptr1;
for (i = 0; i < ovlData->numRel; i++) {
- uint8 *ptr = tempPtr->dataPtr =
- (uint8 *) mallocAndZero(tempPtr->sizeOfData);
-
- if (!ptr) {
- /* releaseScript(scriptIdx,scriptName);
- *
- * if (freeIsNeeded)
- * {
- * freePtr(unpackedBuffer);
- * } */
+ tempPtr->dataPtr = (uint8 *) mallocAndZero(tempPtr->sizeOfData);
+ if (!tempPtr->dataPtr) {
return (-2);
}
- memcpy(ptr, scriptPtr, tempPtr->sizeOfData);
- scriptPtr += tempPtr->sizeOfData;
+ s.read(tempPtr->dataPtr, tempPtr->sizeOfData);
if (tempPtr->offsetToImportData) {
- flipGen(ptr + tempPtr->offsetToImportData,
+ flipGen(tempPtr->dataPtr + tempPtr->offsetToImportData,
tempPtr->numRelocGlob * 10);
}
if (tempPtr->offsetToSubData2) {
- flipGen(ptr + tempPtr->offsetToImportData,
+ flipGen(tempPtr->dataPtr + tempPtr->offsetToSubData2,
tempPtr->subData2Size * 10);
}
@@ -367,8 +380,7 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->ptr8, scriptPtr, ovlData->size12);
- scriptPtr += ovlData->size12;
+ s.read(ovlData->ptr8, ovlData->size12);
}
if (ovlData->numObj) {
@@ -378,47 +390,20 @@ int loadOverlay(const char *scriptName) {
sizeof(objDataStruct));
if (!ovlData->arrayObject) {
-/* releaseScript(scriptIdx,scriptName);
-
- if (freeIsNeeded) {
- freePtr(unpackedBuffer);
- } */
-
return (-2);
}
for (i = 0; i < ovlData->numObj; i++) {
- ovlData->arrayObject[i]._type = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._type);
-
- int16 tempClass = *(int16 *) scriptPtr;
- flipShort(&tempClass);
- ovlData->arrayObject[i]._class = (eClass)tempClass;
- scriptPtr += 2;
-
- ovlData->arrayObject[i]._nameOffset = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._nameOffset);
-
- ovlData->arrayObject[i]._numStates = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._numStates);
-
- ovlData->arrayObject[i]._varTableIdx = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._varTableIdx);
-
- ovlData->arrayObject[i]._firstStateIdx = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._firstStateIdx);
-
- ovlData->arrayObject[i]._stateTableIdx = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->arrayObject[i]._stateTableIdx);
+ ovlData->arrayObject[i]._type = s.readUint16BE();
+ ovlData->arrayObject[i]._class = (eClass) s.readUint16BE();
+ ovlData->arrayObject[i]._nameOffset = s.readUint16BE();
+ ovlData->arrayObject[i]._numStates = s.readUint16BE();
+ ovlData->arrayObject[i]._varTableIdx = s.readUint16BE();
+ ovlData->arrayObject[i]._firstStateIdx = s.readUint16BE();
+ ovlData->arrayObject[i]._stateTableIdx = s.readUint16BE();
}
- // allocte states for object with multiple states
+ // allocate states for object with multiple states
if (scriptNotLoadedBefore) {
overlayTable[scriptIdx].state = stateID;
@@ -430,38 +415,30 @@ int loadOverlay(const char *scriptName) {
ovlData->arrayObjVar =
(objectParams *) mallocAndZero(ovlData->size9 *
sizeof(objectParams));
- memset(ovlData->arrayObjVar, 0,
- ovlData->size9 * sizeof(objectParams));
if (!ovlData->arrayObjVar) {
-/* releaseScript(scriptIdx,scriptName);
-
- if (freeIsNeeded) {
- freePtr(unpackedBuffer);
- } */
-
return (-2);
}
}
if (ovlData->size8) {
+ int i;
ovlData->arrayStates =
(objectParams *) mallocAndZero(ovlData->size8 *
sizeof(objectParams));
if (!ovlData->arrayStates) {
-/* releaseScript(scriptIdx,scriptName);
-
- if (freeIsNeeded) {
- freePtr(unpackedBuffer);
- } */
-
return (-2);
}
- memcpy(ovlData->arrayStates, scriptPtr, ovlData->size8 * 12); // TODO: made read item by item
- scriptPtr += ovlData->size8 * 12;
- flipGen(ovlData->arrayStates, ovlData->size8 * 12);
+ for (i = 0; i < ovlData->size8; i++) {
+ ovlData->arrayStates[i].X = s.readUint16BE();
+ ovlData->arrayStates[i].Y = s.readUint16BE();
+ ovlData->arrayStates[i].Z = s.readUint16BE();
+ ovlData->arrayStates[i].frame = s.readUint16BE();
+ ovlData->arrayStates[i].scale = s.readUint16BE();
+ ovlData->arrayStates[i].state = s.readUint16BE();
+ }
}
if (ovlData->numStrings) {
@@ -472,23 +449,15 @@ int loadOverlay(const char *scriptName) {
sizeof(stringEntryStruct));
for (i = 0; i < ovlData->numStrings; i++) {
- ovlData->stringTable[i].idx = *(int16 *) scriptPtr;
- flipShort(&ovlData->stringTable[i].idx);
- scriptPtr += 2;
+ ovlData->stringTable[i].idx = s.readUint16BE();
}
}
-/* if (freeIsNeeded) {
- freePtr(unpackedBuffer);
- } */
-
if (ovlData->sizeOfData4) {
ovlData->data4Ptr =
(uint8 *) mallocAndZero(ovlData->sizeOfData4);
- memset(ovlData->data4Ptr, 0, ovlData->sizeOfData4);
if (!ovlData->data4Ptr) {
- //releaseScript(scriptIdx,scriptName);
return (-2);
}
}
@@ -516,7 +485,7 @@ int loadOverlay(const char *scriptName) {
unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2;
// TODO: here, can unpack in gfx module buffer
- unpackedBuffer = (char *)mallocAndZero(unpackedSize);
+ unpackedBuffer = (byte *)mallocAndZero(unpackedSize);
if (!unpackedBuffer) {
return (-2);
@@ -538,12 +507,9 @@ int loadOverlay(const char *scriptName) {
loadPakedFileToMem(fileIdx, (uint8 *) unpackedBuffer);
}
- scriptPtr = unpackedBuffer;
-
- memcpy(&ovlData->specialString1Length, scriptPtr, 2);
- scriptPtr += 2;
- flipShort(&ovlData->specialString1Length); // recheck if needed
+ Common::MemoryReadStream s2(unpackedBuffer, unpackedSize);
+ ovlData->specialString1Length = s2.readUint16BE();
if (ovlData->specialString1Length) {
ovlData->nameVerbGlob = (char *) mallocAndZero(ovlData->specialString1Length);
@@ -558,15 +524,10 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->nameVerbGlob, scriptPtr,
- ovlData->specialString1Length);
- scriptPtr += ovlData->specialString1Length;
+ s2.read(ovlData->nameVerbGlob, ovlData->specialString1Length);
}
- memcpy(&ovlData->specialString2Length, scriptPtr, 2);
- scriptPtr += 2;
- flipShort(&ovlData->specialString2Length); // recheck if needed
-
+ ovlData->specialString2Length = s2.readUint16BE();
if (ovlData->specialString2Length) {
ovlData->arrayNameObj = (char *) mallocAndZero(ovlData->specialString2Length);
@@ -581,15 +542,11 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->arrayNameObj, scriptPtr,
- ovlData->specialString2Length);
- scriptPtr += ovlData->specialString2Length;
+ s2.read(ovlData->arrayNameObj, ovlData->specialString2Length);
}
for (i = 0; i < ovlData->numStrings; i++) {
- ovlData->stringTable[i].length = *(int16 *) scriptPtr;
- scriptPtr += 2;
- flipShort(&ovlData->stringTable[i].length);
+ ovlData->stringTable[i].length = s2.readUint16BE();
if (ovlData->stringTable[i].length) {
ovlData->stringTable[i].string =
@@ -607,8 +564,7 @@ int loadOverlay(const char *scriptName) {
return (-2);
}
- memcpy(ovlData->stringTable[i].string, scriptPtr, ovlData->stringTable[i].length);
- scriptPtr += ovlData->stringTable[i].length;
+ s2.read(ovlData->stringTable[i].string, ovlData->stringTable[i].length);
}
}
}
diff --git a/engines/cruise/overlay.h b/engines/cruise/overlay.h
index 7d8b2051e1..7ba90a1449 100644
--- a/engines/cruise/overlay.h
+++ b/engines/cruise/overlay.h
@@ -129,7 +129,7 @@ struct objectParams {
struct ovlDataStruct {
ovlData3Struct *arrayProc;
- uint8 *ptr1;
+ ovlData3Struct *ptr1;
objDataStruct *arrayObject;
objectParams *arrayStates;
objectParams *arrayObjVar;
diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp
index 63edf7cb36..3d8321e420 100644
--- a/engines/cruise/saveload.cpp
+++ b/engines/cruise/saveload.cpp
@@ -465,8 +465,7 @@ void saveCT(Common::OutSaveFile& currentSaveFile) {
void loadSavegameDataSub6(Common::InSaveFile& currentSaveFile) {
int32 var;
- var = currentSaveFile.readUint32LE();
- flipLong(&var);
+ var = currentSaveFile.readUint32BE();
if (var) {
int i;
diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h
index a325de3f36..692d1baeb6 100644
--- a/engines/cruise/vars.h
+++ b/engines/cruise/vars.h
@@ -86,13 +86,12 @@ struct filesData2Struct {
int16 field_2;
};
-struct fileName {
+struct dataFileName {
char name[13];
};
struct setHeaderEntry {
- int16 field_0; // offset ptr part 1
- int16 field_2; // offset ptr part 2
+ int32 field_0; // offset ptr
int16 width;
int16 height;
int16 type; // resource type, ie. sprites 0,1,4,5 and 8
@@ -103,7 +102,7 @@ struct setHeaderEntry {
struct volumeDataStruct {
char ident[10];
- fileName *ptr;
+ dataFileName *ptr;
int16 diskNumber;
int32 size;
};
diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp
index b2ff2631c0..47e2f02184 100644
--- a/engines/cruise/volume.cpp
+++ b/engines/cruise/volume.cpp
@@ -395,12 +395,12 @@ int16 readVolCnf(void) {
}
for (i = 0; i < numOfDisks; i++) {
- fileName *ptr;
+ dataFileName *ptr;
fileHandle.read(&volumeData[i].size, 4);
flipLong(&volumeData[i].size);
- ptr = (fileName *) mallocAndZero(volumeData[i].size);
+ ptr = (dataFileName *) mallocAndZero(volumeData[i].size);
volumeData[i].ptr = ptr;
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
new file mode 100644
index 0000000000..7c5963544c
--- /dev/null
+++ b/engines/dialogs.cpp
@@ -0,0 +1,267 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "base/version.h"
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/events.h"
+
+#include "graphics/scaler.h"
+
+#include "gui/about.h"
+#include "gui/eval.h"
+#include "gui/newgui.h"
+#include "gui/ListWidget.h"
+#include "gui/theme.h"
+
+#include "engines/dialogs.h"
+#include "engines/engine.h"
+#include "engines/metaengine.h"
+
+#ifdef SMALL_SCREEN_DEVICE
+#include "gui/KeysDialog.h"
+#endif
+
+using GUI::CommandSender;
+using GUI::StaticTextWidget;
+using GUI::kButtonWidth;
+using GUI::kButtonHeight;
+using GUI::kBigButtonWidth;
+using GUI::kBigButtonHeight;
+using GUI::kCloseCmd;
+using GUI::kTextAlignCenter;
+using GUI::kTextAlignLeft;
+using GUI::WIDGET_ENABLED;
+
+typedef GUI::OptionsDialog GUI_OptionsDialog;
+typedef GUI::Dialog GUI_Dialog;
+
+GlobalDialog::GlobalDialog(String name)
+ : GUI::Dialog(name) {
+_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;}
+
+enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kRTLCmd = 'RTL ',
+ kChooseCmd = 'CHOS'
+};
+
+MainMenuDialog::MainMenuDialog(Engine *engine)
+ : GlobalDialog("globalmain"), _engine(engine) {
+
+#ifndef DISABLE_FANCY_THEMES
+ _logo = 0;
+ if (g_gui.evaluator()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
+ _logo = new GUI::GraphicsWidget(this, "global_logo");
+ _logo->useThemeTransparency(true);
+ _logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall));
+ } else {
+ new StaticTextWidget(this, "global_title", "ScummVM");
+ }
+#else
+ new StaticTextWidget(this, "global_title", "ScummVM");
+#endif
+
+ new StaticTextWidget(this, "global_version", gScummVMVersionDate);
+
+ new GUI::ButtonWidget(this, "globalmain_resume", "Resume", kPlayCmd, 'P');
+
+// new GUI::ButtonWidget(this, "globalmain_load", "Load", kLoadCmd, 'L');
+// new GUI::ButtonWidget(this, "globalmain_save", "Save", kSaveCmd, 'S');
+
+ new GUI::ButtonWidget(this, "globalmain_options", "Options", kOptionsCmd, 'O');
+
+ new GUI::ButtonWidget(this, "globalmain_about", "About", kAboutCmd, 'A');
+
+ _rtlButton = new GUI::ButtonWidget(this, "globalmain_rtl", "Return to Launcher", kRTLCmd, 'R');
+ // '0' corresponds to the kSupportsRTL MetaEngineFeature
+ _rtlButton->setEnabled(_engine->hasFeature(0));
+
+
+ new GUI::ButtonWidget(this, "globalmain_quit", "Quit", kQuitCmd, 'Q');
+
+ _aboutDialog = new GUI::AboutDialog();
+ _optionsDialog = new ConfigDialog();
+}
+
+MainMenuDialog::~MainMenuDialog() {
+ delete _aboutDialog;
+ delete _optionsDialog;
+}
+
+void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kPlayCmd:
+ close();
+ break;
+ case kOptionsCmd:
+ _optionsDialog->runModal();
+ break;
+ case kAboutCmd:
+ _aboutDialog->runModal();
+ break;
+ case kRTLCmd: {
+ Common::Event eventRTL;
+ eventRTL.type = Common::EVENT_RTL;
+ g_system->getEventManager()->pushEvent(eventRTL);
+ close();
+ }
+ break;
+ case kQuitCmd: {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
+ close();
+ }
+ break;
+ default:
+ GlobalDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void MainMenuDialog::reflowLayout() {
+#ifndef DISABLE_FANCY_THEMES
+ if (g_gui.evaluator()->getVar("global_logo.visible") == 1 && g_gui.theme()->supportsImages()) {
+ if (!_logo)
+ _logo = new GUI::GraphicsWidget(this, "global_logo");
+ _logo->useThemeTransparency(true);
+ _logo->setGfx(g_gui.theme()->getImageSurface(GUI::Theme::kImageLogoSmall));
+
+ GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title");
+ if (title) {
+ removeWidget(title);
+ title->setNext(0);
+ delete title;
+ }
+ } else {
+ GUI::StaticTextWidget *title = (StaticTextWidget *)findWidget("global_title");
+ if (!title)
+ new StaticTextWidget(this, "global_title", "ScummVM");
+
+ if (_logo) {
+ removeWidget(_logo);
+ _logo->setNext(0);
+ delete _logo;
+ _logo = 0;
+ }
+ }
+#endif
+
+ Dialog::reflowLayout();
+}
+
+enum {
+ kOKCmd = 'ok '
+};
+
+enum {
+ kKeysCmd = 'KEYS'
+};
+
+// FIXME: We use the empty string as domain name here. This tells the
+// ConfigManager to use the 'default' domain for all its actions. We do that
+// to get as close as possible to editing the 'active' settings.
+//
+// However, that requires bad & evil hacks in the ConfigManager code,
+// and even then still doesn't work quite correctly.
+// For example, if the transient domain contains 'false' for the 'fullscreen'
+// flag, but the user used a hotkey to switch to windowed mode, then the dialog
+// will display the wrong value anyway.
+//
+// Proposed solution consisting of multiple steps:
+// 1) Add special code to the open() code that reads out everything stored
+// in the transient domain that is controlled by this dialog, and updates
+// the dialog accordingly.
+// 2) Even more code is added to query the backend for current settings, like
+// the fullscreen mode flag etc., and also updates the dialog accordingly.
+// 3) The domain being edited is set to the active game domain.
+// 4) If the dialog is closed with the "OK" button, then we remove everything
+// stored in the transient domain (or at least everything corresponding to
+// switches in this dialog.
+// If OTOH the dialog is closed with "Cancel" we do no such thing.
+//
+// These changes will achieve two things at once: Allow us to get rid of using
+// "" as value for the domain, and in fact provide a somewhat better user
+// experience at the same time.
+ConfigDialog::ConfigDialog()
+ : GUI::OptionsDialog("", "scummconfig") {
+
+ //
+ // Sound controllers
+ //
+
+ addVolumeControls(this, "scummconfig_");
+
+ //
+ // Some misc options
+ //
+
+ // SCUMM has a talkspeed range of 0-9
+ addSubtitleControls(this, "scummconfig_", 9);
+
+ //
+ // Add the buttons
+ //
+
+ new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C');
+
+#ifdef SMALL_SCREEN_DEVICE
+ new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K');
+
+ //
+ // Create the sub dialog(s)
+ //
+
+ _keysDialog = new GUI::KeysDialog();
+#endif
+}
+
+ConfigDialog::~ConfigDialog() {
+#ifdef SMALL_SCREEN_DEVICE
+ delete _keysDialog;
+#endif
+}
+
+void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kKeysCmd:
+
+#ifdef SMALL_SCREEN_DEVICE
+ _keysDialog->runModal();
+#endif
+ break;
+ default:
+ GUI_OptionsDialog::handleCommand (sender, cmd, data);
+ }
+}
+
diff --git a/engines/dialogs.h b/engines/dialogs.h
new file mode 100644
index 0000000000..66ea13b8f1
--- /dev/null
+++ b/engines/dialogs.h
@@ -0,0 +1,77 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef GLOBAL_DIALOGS_H
+#define GLOBAL_DIALOGS_H
+
+#include "common/str.h"
+#include "gui/dialog.h"
+#include "gui/options.h"
+#include "gui/widget.h"
+
+#include "engines/engine.h"
+
+
+class GlobalDialog : public GUI::Dialog {
+public:
+ GlobalDialog(Common::String name);
+
+protected:
+ typedef Common::String String;
+};
+
+
+class MainMenuDialog : public GlobalDialog {
+public:
+ MainMenuDialog(Engine *engine);
+ ~MainMenuDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+
+ virtual void reflowLayout();
+
+protected:
+ Engine *_engine;
+
+ GUI::GraphicsWidget *_logo;
+ GUI::ButtonWidget *_rtlButton;
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
+
+};
+
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
+
+public:
+ ConfigDialog();
+ ~ConfigDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+};
+
+#endif
diff --git a/engines/drascula/actors.cpp b/engines/drascula/actors.cpp
index 10ce415c2c..ff46d8201a 100644
--- a/engines/drascula/actors.cpp
+++ b/engines/drascula/actors.cpp
@@ -28,45 +28,45 @@
namespace Drascula {
void DrasculaEngine::placeIgor() {
- int pos_igor[6] = { 1, 0, igorX, igorY, 54, 61 };
+ int igY = 0;
if (currentChapter == 4) {
- pos_igor[1] = 138;
+ igY = 138;
} else {
if (trackIgor == 3)
- pos_igor[1] = 138;
+ igY = 138;
else if (trackIgor == 1)
- pos_igor[1] = 76;
+ igY = 76;
}
- copyRectClip(pos_igor, frontSurface, screenSurface);
+ copyRect(1, igY, igorX, igorY, 54, 61, frontSurface, screenSurface);
}
void DrasculaEngine::placeDrascula() {
- int pos_dr[6] = { 0, 122, drasculaX, drasculaY, 45, 77 };
+ int drX = 0;
if (trackDrascula == 1)
- pos_dr[0] = 47;
+ drX = 47;
else if (trackDrascula == 0)
- pos_dr[0] = 1;
+ drX = 1;
else if (trackDrascula == 3 && currentChapter == 1)
- pos_dr[0] = 93;
+ drX = 93;
if (currentChapter == 6)
- copyRectClip(pos_dr, drawSurface2, screenSurface);
+ copyRect(drX, 122, drasculaX, drasculaY, 45, 77, drawSurface2, screenSurface);
else
- copyRectClip(pos_dr, backSurface, screenSurface);
+ copyRect(drX, 122, drasculaX, drasculaY, 45, 77, backSurface, screenSurface);
}
void DrasculaEngine::placeBJ() {
- int pos_bj[6] = { 0, 99, bjX, bjY, 26, 76 };
+ int bX = 0;
if (trackBJ == 3)
- pos_bj[0] = 10;
+ bX = 10;
else if (trackBJ == 0)
- pos_bj[0] = 37;
+ bX = 37;
- copyRectClip(pos_bj, drawSurface3, screenSurface);
+ copyRect(bX, 99, bjX, bjY, 26, 76, drawSurface3, screenSurface);
}
void DrasculaEngine::hiccup(int counter) {
@@ -189,7 +189,7 @@ void DrasculaEngine::moveCharacters() {
}
}
- if (currentChapter == 1 || currentChapter == 4 || currentChapter == 5 || currentChapter == 6) {
+ if (currentChapter != 2 && currentChapter != 3) {
if (hare_se_ve == 0) {
increaseFrameNum();
return;
@@ -212,25 +212,29 @@ void DrasculaEngine::moveCharacters() {
if (trackProtagonist == 0) {
curPos[1] = 0;
if (currentChapter == 2)
- copyRectClip(curPos, extraSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 1) {
if (currentChapter == 2)
- copyRectClip(curPos, extraSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 2) {
if (currentChapter == 2)
- copyRectClip(curPos, backSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ backSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], backSurface, screenSurface);
} else {
if (currentChapter == 2)
- copyRectClip(curPos, frontSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ frontSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], frontSurface, screenSurface);
@@ -250,25 +254,29 @@ void DrasculaEngine::moveCharacters() {
if (trackProtagonist == 0) {
curPos[1] = 0;
if (currentChapter == 2)
- copyRectClip(curPos, extraSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 1) {
if (currentChapter == 2)
- copyRectClip(curPos, extraSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 2) {
if (currentChapter == 2)
- copyRectClip(curPos, backSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ backSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], backSurface, screenSurface);
} else {
if (currentChapter == 2)
- copyRectClip(curPos, frontSurface, screenSurface);
+ copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
+ frontSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
factor_red[curY + curHeight], frontSurface, screenSurface);
@@ -288,11 +296,11 @@ void DrasculaEngine::quadrant_1() {
distanceY = (curY + curHeight) - roomY;
if (distanceX < distanceY) {
- curDirection = 0;
+ curDirection = kDirectionUp;
trackProtagonist = 2;
stepX = (int)(distanceX / (distanceY / STEP_Y));
} else {
- curDirection = 7;
+ curDirection = kDirectionUp;
trackProtagonist = 0;
stepY = (int)(distanceY / (distanceX / STEP_X));
}
@@ -309,11 +317,11 @@ void DrasculaEngine::quadrant_2() {
distanceY = (curY + curHeight) - roomY;
if (distanceX < distanceY) {
- curDirection = 1;
+ curDirection = kDirectionRight;
trackProtagonist = 2;
stepX = (int)(distanceX / (distanceY / STEP_Y));
} else {
- curDirection = 2;
+ curDirection = kDirectionRight;
trackProtagonist = 1;
stepY = (int)(distanceY / (distanceX / STEP_X));
}
@@ -330,11 +338,11 @@ void DrasculaEngine::quadrant_3() {
distanceY = roomY - (curY + curHeight);
if (distanceX < distanceY) {
- curDirection = 5;
+ curDirection = kDirectionLeft;
trackProtagonist = 3;
stepX = (int)(distanceX / (distanceY / STEP_Y));
} else {
- curDirection = 6;
+ curDirection = kDirectionLeft;
trackProtagonist = 0;
stepY = (int)(distanceY / (distanceX / STEP_X));
}
@@ -351,11 +359,11 @@ void DrasculaEngine::quadrant_4() {
distanceY = roomY - (curY + curHeight);
if (distanceX < distanceY) {
- curDirection = 4;
+ curDirection = kDirectionDown;
trackProtagonist = 3;
stepX = (int)(distanceX / (distanceY / STEP_Y));
} else {
- curDirection = 3;
+ curDirection = kDirectionDown;
trackProtagonist = 1;
stepY = (int)(distanceY / (distanceX / STEP_X));
}
@@ -370,16 +378,16 @@ void DrasculaEngine::increaseFrameNum() {
if (num_frame == 6)
num_frame = 0;
- if (curDirection == 0 || curDirection == 7) {
+ if (curDirection == kDirectionUp) {
curX -= stepX;
curY -= stepY;
- } else if (curDirection == 1 || curDirection == 2) {
+ } else if (curDirection == kDirectionRight) {
curX += stepX;
curY -= stepY;
- } else if (curDirection == 3 || curDirection == 4) {
+ } else if (curDirection == kDirectionDown) {
curX += stepX;
curY += stepY;
- } else if (curDirection == 5 || curDirection == 6) {
+ } else if (curDirection == kDirectionLeft) {
curX -= stepX;
curY += stepY;
}
@@ -394,13 +402,13 @@ void DrasculaEngine::increaseFrameNum() {
}
void DrasculaEngine::walkDown() {
- curDirection = 4;
+ curDirection = kDirectionDown;
trackProtagonist = 3;
stepX = 0;
}
void DrasculaEngine::walkUp() {
- curDirection = 0;
+ curDirection = kDirectionUp;
trackProtagonist = 2;
stepX = 0;
}
@@ -432,7 +440,8 @@ void DrasculaEngine::moveVonBraun() {
actorFrames[kFrameVonBraun] = 1;
}
- copyRectClip(pos_vb, frontSurface, screenSurface);
+ copyRect(pos_vb[0], pos_vb[1], pos_vb[2], pos_vb[3], pos_vb[4], pos_vb[5],
+ frontSurface, screenSurface);
}
void DrasculaEngine::placeVonBraun(int pointX) {
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index 06868494b5..ad7fe64d0e 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -55,7 +55,7 @@ void DrasculaEngine::updateAnim2(int y, int px, int py, int width, int height, i
// This is the game's introduction sequence
void DrasculaEngine::animation_1_1() {
int l, l2, p;
- int pixelPos[6];
+ //int pixelPos[6];
while (term_int == 0) {
playMusic(29);
@@ -87,7 +87,7 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
color_abc(kColorRed);
- centerText(_textmisc[_lang][1], 160, 100);
+ centerText(_textmisc[1], 160, 100);
updateScreen();
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
@@ -134,7 +134,7 @@ void DrasculaEngine::animation_1_1() {
for (l2 = 0; l2 < 3; l2++)
for (l = 0; l < 7; l++) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface);
updateScreen();
if (getScan() == Common::KEYCODE_ESCAPE) {
@@ -147,19 +147,13 @@ void DrasculaEngine::animation_1_1() {
break;
l2 = 0; p = 0;
- pixelPos[3] = 45;
- pixelPos[4] = 63;
- pixelPos[5] = 31;
for (l = 0; l < 180; l++) {
copyBackground(0, 0, 320 - l, 0, l, 200, drawSurface3, screenSurface);
copyBackground(l, 0, 0, 0, 320 - l, 200, bgSurface, screenSurface);
- pixelPos[0] = interf_x[l2];
- pixelPos[1] = interf_y[l2];
- pixelPos[2] = 156 - l;
-
- copyRectClip(pixelPos, drawSurface2, screenSurface);
+ copyRect(interf_x[l2], interf_y[l2], 156 - l, 45, 63, 31,
+ drawSurface2, screenSurface);
updateScreen();
p++;
if (p == 6) {
@@ -177,7 +171,7 @@ void DrasculaEngine::animation_1_1() {
break;
copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface);
- talk_dr_grande(1);
+ talk_drascula_big(1);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
@@ -193,14 +187,14 @@ void DrasculaEngine::animation_1_1() {
igorX = 66;
igorY = 97;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
talk_igor(8, kIgorDch);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
@@ -219,12 +213,12 @@ void DrasculaEngine::animation_1_1() {
loadPic("plan1.alg", screenSurface, HALF_PAL);
updateScreen();
pause(10);
- talk_solo(_textd[_lang][4],"d4.als");
+ talk_solo(_textd[4],"d4.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
loadPic("plan1.alg", screenSurface, HALF_PAL);
updateScreen();
- talk_solo(_textd[_lang][5], "d5.als");
+ talk_solo(_textd[5], "d5.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
if (animate("lib2.bin", 16))
@@ -233,7 +227,7 @@ void DrasculaEngine::animation_1_1() {
loadPic("plan2.alg", screenSurface, HALF_PAL);
updateScreen();
pause(20);
- talk_solo(_textd[_lang][6], "d6.als");
+ talk_solo(_textd[6], "d6.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
if (animate("lib2.bin", 16))
@@ -244,12 +238,12 @@ void DrasculaEngine::animation_1_1() {
pause(20);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
- talk_solo(_textd[_lang][7], "d7.als");
+ talk_solo(_textd[7], "d7.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
loadPic("plan3.alg", screenSurface, HALF_PAL);
updateScreen();
- talk_solo(_textd[_lang][8], "d8.als");
+ talk_solo(_textd[8], "d8.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
clearRoom();
@@ -297,13 +291,13 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
trackDrascula = 3;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
pause(1);
trackDrascula = 0;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
@@ -311,13 +305,13 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
trackDrascula = 3;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
pause(1);
trackDrascula = 1;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
@@ -329,13 +323,13 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
trackDrascula = 3;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
pause(1);
trackDrascula = 0;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
updateScreen();
@@ -402,9 +396,6 @@ void DrasculaEngine::animation_2_1() {
if (animate("ag.bin", 14))
break;
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an11y13.alg", extraSurface);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
@@ -413,9 +404,6 @@ void DrasculaEngine::animation_2_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
loadPic(97, extraSurface);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
@@ -436,7 +424,7 @@ void DrasculaEngine::animation_2_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
- talk_solo(_textbj[_lang][1], "BJ1.als");
+ talk_solo(_textbj[1], "BJ1.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
clearRoom();
@@ -449,7 +437,7 @@ void DrasculaEngine::animation_2_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
color_solo = kColorYellow;
- talk_solo(_text[_lang][214], "214.als");
+ talk_solo(_text[214], "214.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
clearRoom();
@@ -491,23 +479,8 @@ void DrasculaEngine::animation_2_1() {
curX = 100;
curY = 95;
- talk_bj(2);
- talk(215);
- talk_bj(3);
- talk(216);
- talk_bj(4);
- talk_bj(5);
- talk_bj(6);
- talk(217);
- talk_bj(7);
- talk(218);
- talk_bj(8);
- talk(219);
- talk_bj(9);
- talk(220);
- talk(221);
- talk_bj(10);
- talk(222);
+ playTalkSequence(2); // sequence 2, chapter 1
+
if (animate("gaf.bin", 15))
break;
if (animate("bjb.bin", 14))
@@ -523,7 +496,7 @@ void DrasculaEngine::animation_2_1() {
pause(120);
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
- talk_solo(_text[_lang][223], "223.als");
+ talk_solo(_text[223], "223.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
color_solo = kColorWhite;
@@ -532,7 +505,7 @@ void DrasculaEngine::animation_2_1() {
break;
updateScreen();
pause(110);
- talk_solo(_textbj[_lang][11], "BJ11.als");
+ talk_solo(_textbj[11], "BJ11.als");
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE))
break;
updateRoom();
@@ -596,45 +569,17 @@ void DrasculaEngine::animation_2_1() {
}
}
+// John Hacker talks with the bartender to book a room
void DrasculaEngine::animation_3_1() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an11y13.alg", extraSurface);
- talk(192);
- talk_bartender(1);
- talk(193);
- talk_bartender(2);
- talk(194);
- talk_bartender(3);
- talk(195);
- talk_bartender(4);
- talk(196);
- talk_bartender(5);
- talk_bartender(6);
- talk(197);
- talk_bartender(7);
- talk(198);
- talk_bartender(8);
- talk(199);
- talk_bartender(9);
- talk(200);
- talk(201);
- talk(202);
-
- flags[0] = 1;
-
- if (_lang == kSpanish)
- textSurface = extraSurface;
+ playTalkSequence(3); // sequence 3, chapter 1
loadPic(97, extraSurface);
}
+// John Hacker talks with the pianist
void DrasculaEngine::animation_4_1() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an12.alg", extraSurface);
talk(205);
@@ -666,28 +611,20 @@ void DrasculaEngine::animation_4_1() {
talk_pianist(4);
talk(209);
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
flags[11] = 0;
loadPic(97, extraSurface);
}
-void DrasculaEngine::animation_1_2() {
- gotoObject(178, 121);
- gotoObject(169, 135);
-}
-
void DrasculaEngine::animation_2_2() {
trackProtagonist = 0;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
moveCharacters();
updateRefresh();
updateScreen();
loadPic("an2_1.alg", frontSurface);
loadPic("an2_2.alg", extraSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyBackground(1, 1, 201, 87, 50, 52, frontSurface, screenSurface);
updateScreen();
@@ -701,7 +638,7 @@ void DrasculaEngine::animation_2_2() {
updateAnim(55, 201, 87, 50, 52, 6, extraSurface);
updateAnim(109, 201, 87, 50, 52, 2, extraSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
finishSound();
@@ -713,18 +650,12 @@ void DrasculaEngine::animation_2_2() {
finishSound();
}
-void DrasculaEngine::animation_3_2() {
- gotoObject(163, 106);
- gotoObject(287, 101);
- trackProtagonist = 0;
-}
-
void DrasculaEngine::animation_4_2() {
stopMusic();
flags[9] = 1;
pause(12);
- talk(56);
+ talk(60);
pause(8);
clearRoom();
@@ -734,10 +665,7 @@ void DrasculaEngine::animation_4_2() {
loadPic("ciego4.alg", backSurface);
loadPic("ciego5.alg", frontSurface);
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(10);
@@ -761,13 +689,13 @@ void DrasculaEngine::animation_4_2() {
talk_blind(7);
talk_hacker(63);
talk_blind(8);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
_system->delayMillis(1000);
talk_hacker(64);
talk_blind(9);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(14);
@@ -780,54 +708,25 @@ void DrasculaEngine::animation_4_2() {
loadPic(96, frontSurface);
loadPic(97, extraSurface);
loadPic(99, backSurface);
- withoutVerb();
-
- if (_lang == kSpanish)
- textSurface = extraSurface;
+ selectVerb(0);
flags[9] = 0;
flags[4] = 1;
}
-void DrasculaEngine::animation_8_2() {
- talk_pianist(6);
- talk(358);
- talk_pianist(7);
- talk_pianist(8);
-}
-
-void DrasculaEngine::animation_9_2() {
- talk_pianist(9);
- talk_pianist(10);
- talk_pianist(11);
-}
-
-void DrasculaEngine::animation_10_2() {
- talk_pianist(12);
- talk(361);
- pause(40);
- talk_pianist(13);
- talk(362);
- talk_pianist(14);
- talk(363);
- talk_pianist(15);
- talk(364);
- talk_pianist(16);
-}
-
void DrasculaEngine::animation_14_2() {
- int cabinPos[6] = { 150, 6, 69, -160, 158, 161 };
+ int cY = -160;
int l = 0;
loadPic("an14_2.alg", backSurface);
for (int n = -160; n <= 0; n = n + 5 + l) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
moveCharacters();
moveVonBraun();
- cabinPos[3] = n;
- copyRectClip(cabinPos, backSurface, screenSurface);
+ cY = n;
+ copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface);
updateRefresh();
updateScreen();
l++;
@@ -845,143 +744,64 @@ void DrasculaEngine::animation_14_2() {
loadPic(99, backSurface);
}
-void DrasculaEngine::animation_15_2() {
- talk_drunk(8);
- pause(7);
- talk_drunk(9);
- talk_drunk(10);
- talk_drunk(11);
-}
-
+// The drunk tells us about Von Braun
void DrasculaEngine::animation_16_2() {
+ char curPic[20];
talk_drunk(12);
talk(371);
clearRoom();
+ // FIXME: Track 31 is missing from the soundtrack available
+ // from ScummVM's downloads page, so for now we're using the
+ // Spanish track 29
+#if 1
+ playMusic(30);
+#else
if (_lang == kSpanish)
playMusic(30);
else
playMusic(32);
+#endif
- int key = getScan();
- if (key != 0)
- goto asco;
-
- if (_lang != kSpanish)
- color_abc(kColorDarkGreen);
-
- loadPic("his1.alg", bgSurface, HALF_PAL);
-
- if (_lang == kSpanish)
- black();
-
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
-
- if (_lang != kSpanish)
- centerText(_texthis[_lang][1], 180, 180);
-
- updateScreen();
-
- if (_lang == kSpanish)
- fadeFromBlack(1);
-
- key = getScan();
- if (key != 0)
+ if (getScan() != 0)
goto asco;
- if (_lang == kSpanish)
- _system->delayMillis(3000);
- else
- _system->delayMillis(4000);
-
- key = getScan();
- if (key != 0)
- goto asco;
-
- fadeToBlack(1);
- key = getScan();
- if (key != 0)
- goto asco;
+ color_abc(kColorDarkGreen);
- clearRoom();
- loadPic("his2.alg", bgSurface, HALF_PAL);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
-
- if (_lang != kSpanish)
- centerText(_texthis[_lang][2], 180, 180);
-
- updateScreen();
- key = getScan();
- if (key != 0)
- goto asco;
-
- if (_lang == kSpanish)
- _system->delayMillis(3000);
- else
- _system->delayMillis(4000);
-
- key = getScan();
- if (key != 0)
- goto asco;
-
- fadeToBlack(1);
- key = getScan();
- if (key != 0)
- goto asco;
+ for (int i = 1; i <= 4; i++) {
+ if (i < 4)
+ sprintf(curPic, "his%i.alg", i);
+ else
+ strcpy(curPic, "his4_2.alg");
- clearRoom();
- loadPic("his3.alg", bgSurface, HALF_PAL);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ loadPic(curPic, screenSurface, HALF_PAL);
+ centerText(_texthis[i], 180, 180);
+ updateScreen();
- if (_lang != kSpanish)
- centerText(_texthis[_lang][3], 180, 180);
+ if (getScan() != 0)
+ goto asco;
- updateScreen();
- key = getScan();
- if (key != 0)
- goto asco;
+ delay(3000);
- if (_lang == kSpanish)
- _system->delayMillis(3000);
- else
- _system->delayMillis(4000);
+ if (i < 4) {
+ fadeToBlack(1);
- key = getScan();
- if (key != 0)
- goto asco;
+ if (getScan() != 0)
+ goto asco;
- fadeToBlack(1);
+ clearRoom();
+ }
+ }
- clearRoom();
loadPic("his4_1.alg", bgSurface, HALF_PAL);
loadPic("his4_2.alg", drawSurface3);
- copyBackground(0, 0, 0, 0, 320, 200, drawSurface3, screenSurface);
-
- if (_lang != kSpanish)
- centerText(_texthis[_lang][1], 180, 180);
-
- updateScreen();
- key = getScan();
- if (key != 0)
- goto asco;
-
- if (_lang == kSpanish)
- _system->delayMillis(2000);
- else
- _system->delayMillis(4000);
-
- key = getScan();
- if (key != 0)
- goto asco;
-
for (int l = 1; l < 200; l++) {
copyBackground(0, 0, 0, l, 320, 200 - l, drawSurface3, screenSurface);
copyBackground(0, 200 - l, 0, 0, 320, l, bgSurface, screenSurface);
updateScreen();
- key = getScan();
- if (key != 0)
+ if (getScan() != 0)
goto asco;
}
@@ -1002,34 +822,24 @@ asco:
stopMusic();
}
-void DrasculaEngine::animation_17_2() {
- talk_drunk(13);
- talk_drunk(14);
- flags[40] = 1;
-}
-
-void DrasculaEngine::animation_19_2() {
- talk_vonBraunpuerta(5);
-}
-
void DrasculaEngine::animation_20_2() {
- talk_vonBraunpuerta(7);
- talk_vonBraunpuerta(8);
+ talk_vonBraun(7, kVonBraunDoor);
+ talk_vonBraun(8, kVonBraunDoor);
talk(383);
- talk_vonBraunpuerta(9);
+ talk_vonBraun(9, kVonBraunDoor);
talk(384);
- talk_vonBraunpuerta(10);
+ talk_vonBraun(10, kVonBraunDoor);
talk(385);
- talk_vonBraunpuerta(11);
+ talk_vonBraun(11, kVonBraunDoor);
if (flags[23] == 0) {
talk(350);
- talk_vonBraunpuerta(57);
+ talk_vonBraun(57, kVonBraunDoor);
} else {
talk(386);
- talk_vonBraunpuerta(12);
+ talk_vonBraun(12, kVonBraunDoor);
flags[18] = 0;
flags[14] = 1;
- openDoor(15, 1);
+ toggleDoor(15, 1, kOpenDoor);
exitRoom(1);
animation_23_2();
exitRoom(0);
@@ -1042,36 +852,32 @@ void DrasculaEngine::animation_20_2() {
}
}
-void DrasculaEngine::animation_21_2() {
- talk_vonBraunpuerta(6);
-}
-
void DrasculaEngine::animation_23_2() {
loadPic("an24.alg", frontSurface);
flags[21] = 1;
if (flags[25] == 0) {
- talk_vonBraun(13);
- talk_vonBraun(14);
+ talk_vonBraun(13, kVonBraunDoor);
+ talk_vonBraun(14, kVonBraunDoor);
pause(10);
talk(387);
}
- talk_vonBraun(15);
+ talk_vonBraun(15, kVonBraunNormal);
placeVonBraun(42);
trackVonBraun = 1;
- talk_vonBraun(16);
+ talk_vonBraun(16, kVonBraunNormal);
trackVonBraun = 2;
gotoObject(157, 147);
gotoObject(131, 149);
trackProtagonist = 0;
animation_14_2();
if (flags[25] == 0)
- talk_vonBraun(17);
+ talk_vonBraun(17, kVonBraunNormal);
pause(8);
trackVonBraun = 1;
- talk_vonBraun(18);
+ talk_vonBraun(18, kVonBraunNormal);
if (flags[29] == 0)
animation_23_joined();
@@ -1083,9 +889,9 @@ void DrasculaEngine::animation_23_2() {
placeVonBraun(99);
if (flags[29] == 0) {
- talk_vonBraun(19);
+ talk_vonBraun(19, kVonBraunNormal);
if (flags[25] == 0) {
- talk_vonBraun(20);
+ talk_vonBraun(20, kVonBraunNormal);
if (removeObject(kItemMoney) == 0)
flags[30] = 1;
if (removeObject(kItemTwoCoins) == 0)
@@ -1093,7 +899,7 @@ void DrasculaEngine::animation_23_2() {
if (removeObject(kItemOneCoin) == 0)
flags[32] = 1;
}
- talk_vonBraun(21);
+ talk_vonBraun(21, kVonBraunNormal);
} else
animation_27_2();
@@ -1142,7 +948,7 @@ void DrasculaEngine::animation_23_joined2() {
}
void DrasculaEngine::animation_25_2() {
- int cabinPos[6] = { 150, 6, 69, 0, 158, 161 };
+ int cY = 0;
loadPic("an14_2.alg", backSurface);
loadPic(18, bgSurface);
@@ -1152,15 +958,15 @@ void DrasculaEngine::animation_25_2() {
playSound(6);
for (int n = 0; n >= -160; n = n - 8) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
moveCharacters();
moveVonBraun();
- cabinPos[3] = n;
+ cY = n;
- copyRectClip(cabinPos, backSurface, screenSurface);
+ copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface);
updateRefresh();
updateScreen();
@@ -1174,50 +980,30 @@ void DrasculaEngine::animation_25_2() {
void DrasculaEngine::animation_27_2() {
flags[22] = 1;
- withoutVerb();
+ selectVerb(0);
removeObject(kItemEarWithEarPlug);
addObject(kItemEarplugs);
- talk_vonBraun(23);
- talk_vonBraun(24);
+ talk_vonBraun(23, kVonBraunNormal);
+ talk_vonBraun(24, kVonBraunNormal);
if (flags[30] == 1)
addObject(kItemMoney);
if (flags[31] == 1)
addObject(kItemTwoCoins);
if (flags[32] == 1)
addObject(kItemOneCoin);
- talk_vonBraun(25);
- talk_vonBraun(26);
-}
-
-void DrasculaEngine::animation_28_2() {
- for(int i = 27; i <= 30; i++)
- talk_vonBraun(i);
+ talk_vonBraun(25, kVonBraunNormal);
+ talk_vonBraun(26, kVonBraunNormal);
}
void DrasculaEngine::animation_29_2() {
if (flags[33] == 0) {
- talk_vonBraun(32);
- talk(398);
- talk_vonBraun(33);
- talk(399);
- talk_vonBraun(34);
- talk_vonBraun(35);
- talk(400);
- talk_vonBraun(36);
- talk_vonBraun(37);
- talk(386);
- talk_vonBraun(38);
- talk_vonBraun(39);
- talk(401);
- talk_vonBraun(40);
- talk_vonBraun(41);
- flags[33] = 1;
+ playTalkSequence(29); // sequence 29, chapter 2
} else
- talk_vonBraun(43);
+ talk_vonBraun(43, kVonBraunNormal);
talk(402);
- talk_vonBraun(42);
+ talk_vonBraun(42, kVonBraunNormal);
if (flags[38] == 0) {
talk(403);
@@ -1226,50 +1012,16 @@ void DrasculaEngine::animation_29_2() {
talk(386);
}
-void DrasculaEngine::animation_30_2() {
- talk_vonBraun(31);
- talk(396);
-}
-
void DrasculaEngine::animation_31_2() {
- talk_vonBraun(44);
+ talk_vonBraun(44, kVonBraunNormal);
placeVonBraun(-50);
pause(15);
gotoObject(159, 140);
loadPic(99, backSurface);
- trackProtagonist = 2;
- updateRoom();
- updateScreen();
- pause(78);
- trackProtagonist = 0;
- updateRoom();
- updateScreen();
- pause(22);
- talk(406);
- placeVonBraun(98);
- talk_vonBraun(45);
- talk_vonBraun(46);
- talk_vonBraun(47);
- talk(407);
- talk_vonBraun(48);
- talk_vonBraun(49);
- talk(408);
- talk_vonBraun(50);
- talk_vonBraun(51);
- talk(409);
- talk_vonBraun(52);
- talk_vonBraun(53);
- pause(12);
- talk_vonBraun(54);
- talk_vonBraun(55);
- talk(410);
- talk_vonBraun(56);
- breakOut = 1;
+ playTalkSequence(31); // sequence 31, chapter 2
- flags[38] = 0;
- flags[36] = 1;
- withoutVerb();
+ selectVerb(0);
removeObject(kItemLeaves);
removeObject(kItemBubbleGum);
removeObject(kItemTissues);
@@ -1293,7 +1045,7 @@ void DrasculaEngine::animation_35_2() {
updateAnim(1, 70, 90, 46, 80, 6, frontSurface);
updateAnim(82, 70, 90, 46, 80, 2, frontSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
@@ -1308,13 +1060,6 @@ void DrasculaEngine::animation_35_2() {
fadeToBlack(2);
}
-void DrasculaEngine::animation_1_3() {
- talk(413);
- grr();
- pause(50);
- talk(414);
-}
-
void DrasculaEngine::animation_2_3() {
flags[0] = 1;
playMusic(13);
@@ -1396,7 +1141,7 @@ void DrasculaEngine::animation_6_3() {
for (frame = 0; frame < 6; frame++) {
pause(3);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyRect(yoda_x[frame], yoda_y[frame], px, py, 78, 90, frontSurface, screenSurface);
updateScreen(px, py, px, py, 78, 90, screenSurface);
}
@@ -1436,29 +1181,6 @@ void DrasculaEngine::animation_ray() {
finishSound();
}
-void DrasculaEngine::animation_2_4() {
- talk_igor(16, kIgorSeated);
- talk(278);
- talk_igor(17, kIgorSeated);
- talk(279);
- talk_igor(18, kIgorSeated);
-}
-
-void DrasculaEngine::animation_3_4() {
- talk_igor(19, kIgorSeated);
- talk_igor(20, kIgorSeated);
- talk(281);
-}
-
-void DrasculaEngine::animation_4_4() {
- talk(287);
- talk_igor(21, kIgorSeated);
- talk(284);
- talk_igor(22, kIgorSeated);
- talk(285);
- talk_igor(23, kIgorSeated);
-}
-
void DrasculaEngine::animation_7_4() {
black();
talk(427);
@@ -1512,37 +1234,6 @@ void DrasculaEngine::animation_1_5() {
converse(8);
}
-void DrasculaEngine::animation_2_5() {
- talk_bj(22);
-}
-
-void DrasculaEngine::animation_3_5() {
- talk_bj(23);
- pickObject(10);
- breakOut = 1;
-}
-
-void DrasculaEngine::animation_4_5() {
- flags[7] = 1;
- updateRoom();
- updateScreen();
- talk(228);
- talk_werewolf(1);
- talk_werewolf(2);
- pause(23);
- talk(229);
- talk_werewolf(3);
- talk_werewolf(4);
- talk(230);
- talk_werewolf(5);
- talk(231);
- talk_werewolf(6);
- talk_werewolf(7);
- pause(33);
- talk(232);
- talk_werewolf(8);
-}
-
void DrasculaEngine::animation_5_5(){
int h;
int frame = 0;
@@ -1551,7 +1242,7 @@ void DrasculaEngine::animation_5_5(){
int flyX[] = {1, 63, 125, 187, 249};
int pixelX = curX - 53, pixelY = curY - 9;
- withoutVerb();
+ selectVerb(0);
removeObject(8);
gotoObject(curX - 19, curY + curHeight);
@@ -1564,7 +1255,7 @@ void DrasculaEngine::animation_5_5(){
for (frame = 0; frame < 9; frame++) {
pause(3);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, backSurface, screenSurface);
updateScreen(pixelX, pixelY, pixelX,pixelY, 97,64, screenSurface);
}
@@ -1574,7 +1265,7 @@ void DrasculaEngine::animation_5_5(){
for (frame = 0; frame < 9; frame++) {
pause(3);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyRect(boneX[frame], boneY[frame], pixelX, pixelY, 97, 64, frontSurface, screenSurface);
updateScreen(pixelX, pixelY, pixelX,pixelY, 97, 64, screenSurface);
}
@@ -1618,41 +1309,6 @@ void DrasculaEngine::animation_5_5(){
loadPic(49, bgSurface, HALF_PAL);
}
-void DrasculaEngine::animation_6_5() {
- talk_werewolf(9);
- talk(234);
-}
-
-void DrasculaEngine::animation_7_5() {
- talk_werewolf(10);
- talk(236);
- talk_werewolf(11);
- talk_werewolf(12);
- talk_werewolf(13);
- pause(34);
- talk_werewolf(14);
-}
-
-void DrasculaEngine::animation_8_5() {
- talk_werewolf(15);
- talk(238);
- talk_werewolf(16);
-}
-
-void DrasculaEngine::animation_9_5() {
- flags[4] = 1;
- talk(401);
- withoutVerb();
- removeObject(15);
-}
-
-void DrasculaEngine::animation_10_5() {
- flags[3] = 1;
- talk(401);
- withoutVerb();
- removeObject(12);
-}
-
void DrasculaEngine::animation_11_5() {
flags[9] = 1;
if (flags[2] == 1 && flags[3] == 1 && flags[4] == 1)
@@ -1686,7 +1342,7 @@ void DrasculaEngine::animation_12_5() {
updateRoom();
updateScreen();
- setDarkPalette();
+ setDefaultPalette(darkPalette);
for (color = 0; color < 255; color++)
for (component = 0; component < 3; component++) {
@@ -1742,7 +1398,7 @@ void DrasculaEngine::animation_12_5() {
animate("frel.bin", 16);
clearRoom();
- setBrightPalette();
+ setDefaultPalette(brightPalette);
setPalette((byte *)&gamePalette);
flags[1] = 1;
@@ -1765,7 +1421,7 @@ void DrasculaEngine::animation_12_5() {
characterMoved = 0;
curX = -1;
objExit = 104;
- withoutVerb();
+ selectVerb(0);
enterRoom(57);
}
@@ -1774,12 +1430,11 @@ void DrasculaEngine::animation_13_5() {
int frame = 0;
int frus_x[] = {1, 46, 91, 136, 181, 226, 271};
int frus_y[] = {1, 1, 1, 1, 1, 1, 1, 89};
- int pos_frusky[6] = { 1, 1, frank_x, 81, 44, 87 };
loadPic("auxfr.alg", backSurface);
updateRoom();
- copyRectClip(pos_frusky, backSurface, screenSurface);
+ copyRect(1, 1, frank_x, 81, 44, 87, backSurface, screenSurface);
updateScreen();
pause(15);
@@ -1787,10 +1442,7 @@ void DrasculaEngine::animation_13_5() {
for (;;) {
updateRoom();
- pos_frusky[0] = frus_x[frame];
- pos_frusky[1] = frus_y[frame];
- pos_frusky[2] = frank_x;
- copyRectClip( pos_frusky, backSurface, screenSurface);
+ copyRect(frus_x[frame], frus_y[frame], frank_x, 81, 44, 87, backSurface, screenSurface);
updateScreen();
frank_x -= 5;
frame++;
@@ -1823,26 +1475,10 @@ void DrasculaEngine::animation_14_5() {
trackProtagonist = 3;
updateRoom();
updateScreen();
- talk_solo(_textd[_lang][18], "d18.als");
+ talk_solo(_textd[18], "d18.als");
fadeToBlack(1);
}
-void DrasculaEngine::animation_15_5() {
- talk_mus(4);
- talk_mus(5);
- talk_mus(6);
- talk(291);
- talk_mus(7);
-}
-
-void DrasculaEngine::animation_16_5() {
- talk_mus(8);
-}
-
-void DrasculaEngine::animation_17_5() {
- talk_mus(9);
-}
-
void DrasculaEngine::animation_1_6() {
trackProtagonist = 0;
curX = 103;
@@ -1909,36 +1545,21 @@ void DrasculaEngine::animation_1_6() {
trackDrascula = 0;
talk_drascula(35);
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
clearRoom();
enterRoom(102);
activatePendulum();
}
-void DrasculaEngine::animation_2_6() {
- talk_drascula(24, 1);
-}
-
-void DrasculaEngine::animation_3_6() {
- talk_drascula(24, 1);
-}
-
-void DrasculaEngine::animation_4_6() {
- talk_drascula(25, 1);
-}
-
void DrasculaEngine::animation_5_6() {
- int pos_pen[6] = { 1, 29, 204, -125, 18, 125 };
+ int pY = -125;
animate("man.bin", 14);
for (int n = -125; n <= 0; n = n + 2) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
- pos_pen[3] = n;
- copyRectClip(pos_pen, drawSurface3, screenSurface);
+ pY = n;
+ copyRect(1, 29, 204, pY, 18, 125, drawSurface3, screenSurface);
updateRefresh();
@@ -1952,7 +1573,7 @@ void DrasculaEngine::animation_5_6() {
void DrasculaEngine::animation_6_6() {
animate("rct.bin", 11);
clearRoom();
- withoutVerb();
+ selectVerb(0);
removeObject(20);
loadPic(96, frontSurface);
loadPic(97, frontSurface);
@@ -1961,7 +1582,7 @@ void DrasculaEngine::animation_6_6() {
doBreak = 1;
objExit = 104;
curX = -1;
- withoutVerb();
+ selectVerb(0);
enterRoom(58);
hare_se_ve = 1;
trackProtagonist = 1;
@@ -1973,11 +1594,6 @@ void DrasculaEngine::animation_6_6() {
flags[2] = 1;
}
-void DrasculaEngine::animation_7_6() {
- flags[8] = 1;
- updateVisible();
-}
-
void DrasculaEngine::animation_9_6() {
int v_cd;
@@ -2014,11 +1630,11 @@ void DrasculaEngine::animation_9_6() {
clearRoom();
loadPic("nota.alg", bgSurface, COMPLETE_PAL);
color_abc(kColorWhite);
- talk_solo(_textbj[_lang][24], "bj24.als");
- talk_solo(_textbj[_lang][25], "bj25.als");
- talk_solo(_textbj[_lang][26], "bj26.als");
- talk_solo(_textbj[_lang][27], "bj27.als");
- talk_solo(_textbj[_lang][28], "bj28.als");
+ talk_solo(_textbj[24], "bj24.als");
+ talk_solo(_textbj[25], "bj25.als");
+ talk_solo(_textbj[26], "bj26.als");
+ talk_solo(_textbj[27], "bj27.als");
+ talk_solo(_textbj[28], "bj28.als");
trackProtagonist = 3;
clearRoom();
loadPic(96, frontSurface, COMPLETE_PAL);
@@ -2033,7 +1649,7 @@ void DrasculaEngine::animation_9_6() {
copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface);
updateScreen();
color_abc(kColorLightGreen);
- talk_solo(_textmisc[_lang][2], "s15.als");
+ talk_solo(_textmisc[2], "s15.als");
loadPic("nota2.alg", bgSurface);
trackProtagonist = 0;
updateRoom();
@@ -2054,54 +1670,8 @@ void DrasculaEngine::animation_9_6() {
stopMusic();
}
-void DrasculaEngine::animation_10_6() {
- playSound(14);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
- updateRefresh_pre();
- copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface);
- updateScreen();
- finishSound();
- talk_bartender(23, 1);
- flags[7] = 1;
-}
-
-void DrasculaEngine::animation_11_6() {
- talk_bartender(10, 1);
- talk(268);
- talk_bartender(11, 1);
-}
-
-void DrasculaEngine::animation_12_6() {
- talk_bartender(12, 1);
- talk(270);
- talk_bartender(13, 1);
- talk_bartender(14, 1);
-}
-
-void DrasculaEngine::animation_13_6() {
- talk_bartender(15, 1);
-}
-
-void DrasculaEngine::animation_14_6() {
- talk_bartender(24, 1);
- addObject(21);
- flags[10] = 1;
- breakOut = 1;
-}
-
-void DrasculaEngine::animation_15_6() {
- talk_bartender(16, 1);
-}
-
-void DrasculaEngine::animation_18_6() {
- flags[6] = 1;
- withoutVerb();
- removeObject(21);
- animate("beb.bin", 10);
-}
-
void DrasculaEngine::animation_19_6() {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyBackground(140, 23, 161, 69, 35, 80, drawSurface3, screenSurface);
updateRefresh_pre();
@@ -2116,9 +1686,6 @@ void DrasculaEngine::animation_19_6() {
}
void DrasculaEngine::animation_12_2() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an12.alg", extraSurface);
talk(356);
@@ -2144,17 +1711,11 @@ void DrasculaEngine::animation_12_2() {
talk_pianist(5);
converse(1);
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
flags[11] = 0;
loadPic(974, extraSurface);
}
void DrasculaEngine::animation_26_2() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an12.alg", extraSurface);
talk(392);
@@ -2205,9 +1766,6 @@ void DrasculaEngine::animation_26_2() {
pickObject(11);
removeObject(kItemBook);
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
flags[11] = 0;
flags[39] = 1;
loadPic(974, extraSurface);
@@ -2215,23 +1773,9 @@ void DrasculaEngine::animation_26_2() {
}
void DrasculaEngine::animation_11_2() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an11y13.alg", extraSurface);
- talk(352);
- talk_bartender(1);
- talk(353);
- talk_bartender(17);
- talk(354);
- talk_bartender(18);
- talk(355);
- pause(40);
- talk_bartender(82);
-
- if (_lang == kSpanish)
- textSurface = extraSurface;
+ playTalkSequence(11); // sequence 11, chapter 2
loadPic(974, extraSurface);
}
@@ -2240,47 +1784,12 @@ void DrasculaEngine::animation_13_2() {
loadPic("an11y13.alg", frontSurface);
if (flags[41] == 0) {
- talk(103);
- talk_drunk(4);
- flags[12] = 1;
- talk(367);
- talk_drunk(5);
- flags[12] = 1;
- talk(368);
- talk_drunk(6);
- talk_drunk(7);
- flags[41] = 1;
+ playTalkSequence(13); // sequence 13, chapter 2
}
- converse(2);
loadPic(964, frontSurface);
}
-void DrasculaEngine::animation_18_2() {
- talk(378);
- talk_vonBraunpuerta(4);
- converse(3);
-}
-
-void DrasculaEngine::animation_22_2() {
- talk(374);
-
- trackProtagonist=2;
- updateRoom();
- updateScreen();
- playSound(13);
- finishSound();
- trackProtagonist = 1;
-
- talk_vonBraunpuerta(1);
- talk(375);
- talk_vonBraunpuerta(2);
- talk(376);
- talk_vonBraunpuerta(3);
-
- flags[18] = 1;
-}
-
void DrasculaEngine::animation_24_2() {
if (curX < 178)
gotoObject(208, 136);
@@ -2297,7 +1806,7 @@ void DrasculaEngine::animation_24_2() {
flags[21] = 1;
- talk_vonBraun(22);
+ talk_vonBraun(22, kVonBraunNormal);
if (flags[22] == 0)
converse(4);
@@ -2360,9 +1869,6 @@ void DrasculaEngine::animation_34_2() {
}
void DrasculaEngine::animation_36_2() {
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
loadPic("an11y13.alg", extraSurface);
talk(404);
@@ -2373,9 +1879,6 @@ void DrasculaEngine::animation_36_2() {
pause(40);
talk_bartender(82);
- if (_lang == kSpanish)
- textSurface = extraSurface;
-
loadPic(974, extraSurface);
}
@@ -2387,7 +1890,7 @@ void DrasculaEngine::animation_7_2() {
if (flags[3] == 1)
copyBackground(258, 110, 85, 44, 23, 53, drawSurface3, bgSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
@@ -2467,17 +1970,14 @@ void DrasculaEngine::animation_5_2() {
loadPic("aux5.alg", drawSurface3);
flags[8] = 1;
curX = curX - 4;
- talk_sync(_text[_lang][46], "46.als", "4442444244244");
- withoutVerb();
+ talk_sync(_text[46], "46.als", "4442444244244");
+ selectVerb(0);
}
void DrasculaEngine::animation_6_2() {
stopMusic();
flags[9] = 1;
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
clearRoom();
loadPic("ciego1.alg", bgSurface, HALF_PAL); // ciego = blind
loadPic("ciego2.alg", drawSurface3);
@@ -2485,7 +1985,7 @@ void DrasculaEngine::animation_6_2() {
loadPic("ciego4.alg", backSurface);
loadPic("ciego5.alg", frontSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(1);
@@ -2497,7 +1997,7 @@ void DrasculaEngine::animation_6_2() {
pause(4);
talk_hacker(67);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(10);
@@ -2510,10 +2010,7 @@ void DrasculaEngine::animation_6_2() {
loadPic(96, frontSurface);
loadPic(97, extraSurface);
loadPic(99, backSurface);
- withoutVerb();
-
- if (_lang == kSpanish)
- textSurface = extraSurface;
+ selectVerb(0);
flags[9] = 0;
}
@@ -2523,7 +2020,7 @@ void DrasculaEngine::animation_33_2() {
flags[9] = 1;
pause(12);
- talk(56);
+ talk(60);
pause(8);
clearRoom();
@@ -2533,10 +2030,7 @@ void DrasculaEngine::animation_33_2() {
loadPic("ciego4.alg", backSurface);
loadPic("ciego5.alg", frontSurface);
- if (_lang == kSpanish)
- textSurface = frontSurface;
-
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(10);
@@ -2549,7 +2043,7 @@ void DrasculaEngine::animation_33_2() {
talk_blind(10);
talk_hacker(65);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
pause(14);
@@ -2562,10 +2056,7 @@ void DrasculaEngine::animation_33_2() {
loadPic(96, frontSurface);
loadPic(97, extraSurface);
loadPic(99, backSurface);
- withoutVerb();
-
- if (_lang == kSpanish)
- textSurface = extraSurface;
+ selectVerb(0);
flags[33] = 1;
flags[9] = 0;
@@ -2642,7 +2133,7 @@ void DrasculaEngine::animation_5_4(){
curY = 82;
updateRoom();
updateScreen();
- openDoor(2, 0);
+ toggleDoor(2, 0, kOpenDoor);
loadPic("auxigor.alg", frontSurface);
igorX = 100;
igorY = 65;
@@ -2663,7 +2154,7 @@ void DrasculaEngine::animation_6_4() {
loadPic(26, bgSurface, HALF_PAL);
loadPic("aux26.alg", drawSurface3);
loadPic("auxigor.alg", frontSurface);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
update_26_pre();
igorX = 104;
igorY = 71;
@@ -2676,7 +2167,7 @@ void DrasculaEngine::animation_6_4() {
loadPic(96, frontSurface);
loadPic(roomDisk, drawSurface3);
loadPic(roomNumber, bgSurface, HALF_PAL);
- withoutVerb();
+ selectVerb(0);
updateRoom();
}
@@ -2693,12 +2184,7 @@ void DrasculaEngine::animation_8_4() {
}
loadPic(96, frontSurface);
- openDoor(7, 2);
-}
-
-void DrasculaEngine::animation_9_4() {
- animate("st.bin", 14);
- fadeToBlack(1);
+ toggleDoor(7, 2, kOpenDoor);
}
void DrasculaEngine::activatePendulum() {
diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp
index 1c3831e4ca..cef1a17486 100644
--- a/engines/drascula/converse.cpp
+++ b/engines/drascula/converse.cpp
@@ -27,38 +27,128 @@
namespace Drascula {
+void DrasculaEngine::playTalkSequence(int sequence) {
+ bool seen = false;
+
+ for (int i = 0; i < _talkSequencesSize; i++) {
+ if (_talkSequences[i].chapter == currentChapter &&
+ _talkSequences[i].sequence == sequence) {
+ seen = true;
+
+ doTalkSequenceCommand(_talkSequences[i]);
+ } else if (seen) // Stop searching down the list
+ break;
+ }
+}
+
+void DrasculaEngine::doTalkSequenceCommand(TalkSequenceCommand cmd) {
+ switch (cmd.commandType) {
+ case kPause:
+ pause(cmd.action);
+ break;
+ case kSetFlag:
+ flags[cmd.action] = 1;
+ break;
+ case kClearFlag:
+ flags[cmd.action] = 0;
+ break;
+ case kPickObject:
+ pickObject(cmd.action);
+ break;
+ case kAddObject:
+ addObject(cmd.action);
+ break;
+ case kBreakOut:
+ breakOut = 1;
+ break;
+ case kConverse:
+ converse(cmd.action);
+ break;
+ case kPlaceVB:
+ placeVonBraun(cmd.action);
+ break;
+ case kUpdateRoom:
+ updateRoom();
+ break;
+ case kUpdateScreen:
+ updateScreen();
+ break;
+ case kTrackProtagonist:
+ trackProtagonist = cmd.action;
+ break;
+ case kPlaySound:
+ playSound(cmd.action);
+ break;
+ case kFinishSound:
+ finishSound();
+ break;
+ case kTalkerGeneral:
+ talk(cmd.action);
+ break;
+ case kTalkerDrunk:
+ talk_drunk(cmd.action);
+ break;
+ case kTalkerPianist:
+ talk_pianist(cmd.action);
+ break;
+ case kTalkerBJ:
+ talk_bj(cmd.action);
+ break;
+ case kTalkerVBNormal:
+ talk_vonBraun(cmd.action, kVonBraunNormal);
+ break;
+ case kTalkerVBDoor:
+ talk_vonBraun(cmd.action, kVonBraunDoor);
+ break;
+ case kTalkerIgorSeated:
+ talk_igor(cmd.action, kIgorSeated);
+ break;
+ case kTalkerWerewolf:
+ talk_werewolf(cmd.action);
+ break;
+ case kTalkerMus:
+ talk_mus(cmd.action);
+ break;
+ case kTalkerDrascula:
+ talk_drascula(cmd.action, 1);
+ break;
+ case kTalkerBartender0:
+ talk_bartender(cmd.action, 0);
+ break;
+ case kTalkerBartender1:
+ talk_bartender(cmd.action, 1);
+ break;
+ default:
+ error("doTalkSequenceCommand: Unknown command: %d", cmd.commandType);
+ }
+}
+
+void DrasculaEngine::cleanupString(char *string) {
+ uint len = strlen(string);
+ for (uint h = 0; h < len; h++)
+ if (string[h] == (char)0xa7)
+ string[h] = ' ';
+}
+
void DrasculaEngine::converse(int index) {
char fileName[20];
sprintf(fileName, "op_%d.cal", index);
- uint h;
- int game1 = 1, game2 = 1, game3 = 1, game4 = 1;
- char phrase1[78];
- char phrase2[78];
- char phrase3[87];
- char phrase4[78];
- char sound1[13];
- char sound2[13];
- char sound3[13];
- char sound4[13];
- int answer1;
- int answer2;
- int answer3;
- int used1 = 0;
- int used2 = 0;
- int used3 = 0;
+ _arj.open(fileName);
+ if (!_arj.isOpen())
+ error("missing data file %s", fileName);
+
+ int size = _arj.size();
+ int game1 = kDialogOptionUnselected,
+ game2 = kDialogOptionUnselected,
+ game3 = kDialogOptionUnselected;
+ char phrase1[78], phrase2[78], phrase3[78], phrase4[78];
+ char sound1[13], sound2[13], sound3[13], sound4[13];
+ int answer1, answer2, answer3;
char buffer[256];
- uint len;
breakOut = 0;
- if (currentChapter == 5)
- withoutVerb();
-
- _arj.open(fileName);
- if (!_arj.isOpen()) {
- error("missing data file %s", fileName);
- }
- int size = _arj.size();
+ selectVerb(0);
getStringFromLine(buffer, size, phrase1);
getStringFromLine(buffer, size, phrase2);
@@ -75,222 +165,131 @@ void DrasculaEngine::converse(int index) {
_arj.close();
if (currentChapter == 2 && !strcmp(fileName, "op_5.cal") && flags[38] == 1 && flags[33] == 1) {
- strcpy(phrase3, _text[_lang][405]);
+ strcpy(phrase3, _text[405]);
strcpy(sound3, "405.als");
answer3 = 31;
}
if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[7] == 1) {
- strcpy(phrase3, _text[_lang][273]);
+ strcpy(phrase3, _text[273]);
strcpy(sound3, "273.als");
answer3 = 14;
}
if (currentChapter == 6 && !strcmp(fileName, "op_12.cal") && flags[10] == 1) {
- strcpy(phrase3, _text[_lang][274]);
+ strcpy(phrase3, _text[274]);
strcpy(sound3, "274.als");
answer3 = 15;
}
- len = strlen(phrase1);
- for (h = 0; h < len; h++)
- if (phrase1[h] == (char)0xa7)
- phrase1[h] = ' ';
-
- len = strlen(phrase2);
- for (h = 0; h < len; h++)
- if (phrase2[h] == (char)0xa7)
- phrase2[h] = ' ';
-
- len = strlen(phrase3);
- for (h = 0; h < len; h++)
- if (phrase3[h] == (char)0xa7)
- phrase3[h] = ' ';
-
- len = strlen(phrase4);
- for (h = 0; h < len; h++)
- if (phrase4[h] == (char)0xa7)
- phrase4[h] = ' ';
+ cleanupString(phrase1);
+ cleanupString(phrase2);
+ cleanupString(phrase3);
+ cleanupString(phrase4);
loadPic("car.alg", backSurface);
// TODO code here should limit y position for mouse in dialog menu,
- // but we can't implement this due lack backend functionality
+ // but we can't implement this as there is lack in backend functionality
// from 1(top) to 31
color_abc(kColorLightGreen);
while (breakOut == 0) {
updateRoom();
- if (currentChapter == 1 || currentChapter == 4 || currentChapter == 6) {
- if (musicStatus() == 0 && flags[11] == 0)
- playMusic(roomMusic);
- } else if (currentChapter == 2) {
- if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0)
- playMusic(roomMusic);
- } else if (currentChapter == 3 || currentChapter == 5) {
- if (musicStatus() == 0)
+ if (musicStatus() == 0 && roomMusic != 0) {
+ if (currentChapter == 3 || currentChapter == 5) {
playMusic(roomMusic);
+ } else { // chapters 1, 2, 4, 6
+ if (flags[11] == 0)
+ playMusic(roomMusic);
+ }
}
updateEvents();
+ print_abc_opc(phrase1, 2, game1);
+ print_abc_opc(phrase2, 10, game2);
+ print_abc_opc(phrase3, 18, game3);
+ print_abc_opc(phrase4, 26, kDialogOptionUnselected);
+
if (mouseY > 0 && mouseY < 9) {
- if (used1 == 1 && _color != kColorWhite)
+ if (game1 == kDialogOptionClicked && _color != kColorWhite)
color_abc(kColorWhite);
- else if (used1 == 0 && _color != kColorLightGreen)
+ else if (game1 != kDialogOptionClicked && _color != kColorLightGreen)
color_abc(kColorLightGreen);
+
+ print_abc_opc(phrase1, 2, kDialogOptionSelected);
+
+ if (leftMouseButton == 1) {
+ delay(100);
+ game1 = kDialogOptionClicked;
+ talk(phrase1, sound1);
+ response(answer1);
+ }
} else if (mouseY > 8 && mouseY < 17) {
- if (used2 == 1 && _color != kColorWhite)
+ if (game2 == kDialogOptionClicked && _color != kColorWhite)
color_abc(kColorWhite);
- else if (used2 == 0 && _color != kColorLightGreen)
+ else if (game2 != kDialogOptionClicked && _color != kColorLightGreen)
color_abc(kColorLightGreen);
+
+ print_abc_opc(phrase2, 10, kDialogOptionSelected);
+
+ if (leftMouseButton == 1) {
+ delay(100);
+ game2 = kDialogOptionClicked;
+ talk(phrase2, sound2);
+ response(answer2);
+ }
} else if (mouseY > 16 && mouseY < 25) {
- if (used3 == 1 && _color != kColorWhite)
+ if (game3 == kDialogOptionClicked && _color != kColorWhite)
color_abc(kColorWhite);
- else if (used3 == 0 && _color != kColorLightGreen)
+ else if (game3 != kDialogOptionClicked && _color != kColorLightGreen)
color_abc(kColorLightGreen);
- } else if (_color != kColorLightGreen)
- color_abc(kColorLightGreen);
- if (mouseY > 0 && mouseY < 9)
- game1 = 2;
- else if (mouseY > 8 && mouseY < 17)
- game2 = 2;
- else if (mouseY > 16 && mouseY < 25)
- game3 = 2;
- else if (mouseY > 24 && mouseY < 33)
- game4 = 2;
+ print_abc_opc(phrase3, 18, kDialogOptionSelected);
- print_abc_opc(phrase1, 1, 2, game1);
- print_abc_opc(phrase2, 1, 10, game2);
- print_abc_opc(phrase3, 1, 18, game3);
- print_abc_opc(phrase4, 1, 26, game4);
-
- updateScreen();
-
- if ((leftMouseButton == 1) && (game1 == 2)) {
- delay(100);
- used1 = 1;
- talk(phrase1, sound1);
- if (currentChapter == 3)
- grr();
- else
- response(answer1);
- } else if ((leftMouseButton == 1) && (game2 == 2)) {
- delay(100);
- used2 = 1;
- talk(phrase2, sound2);
- if (currentChapter == 3)
- grr();
- else
- response(answer2);
- } else if ((leftMouseButton == 1) && (game3 == 2)) {
- delay(100);
- used3 = 1;
- talk(phrase3, sound3);
- if (currentChapter == 3)
- grr();
- else
+ if (leftMouseButton == 1) {
+ delay(100);
+ game3 = kDialogOptionClicked;
+ talk(phrase3, sound3);
response(answer3);
- } else if ((leftMouseButton == 1) && (game4 == 2)) {
- delay(100);
- talk(phrase4, sound4);
- breakOut = 1;
- }
+ }
+ } else if (mouseY > 24 && mouseY < 33) {
+ print_abc_opc(phrase4, 26, kDialogOptionSelected);
- if (leftMouseButton == 1) {
- delay(100);
+ if (leftMouseButton == 1) {
+ delay(100);
+ talk(phrase4, sound4);
+ breakOut = 1;
+ }
+ } else if (_color != kColorLightGreen)
color_abc(kColorLightGreen);
- }
- game1 = (used1 == 0) ? 1 : 3;
- game2 = (used2 == 0) ? 1 : 3;
- game3 = (used3 == 0) ? 1 : 3;
- game4 = 1;
+ updateScreen();
} // while (breakOut == 0)
if (currentChapter == 2)
loadPic(menuBackground, backSurface);
else
loadPic(99, backSurface);
- if (currentChapter != 5)
- withoutVerb();
}
void DrasculaEngine::response(int function) {
- if (currentChapter == 1) {
- if (function >= 10 && function <= 12)
- talk_drunk(function - 9);
- } else if (currentChapter == 2) {
- if (function == 8)
- animation_8_2();
- else if (function == 9)
- animation_9_2();
- else if (function == 10)
- animation_10_2();
- else if (function == 15)
- animation_15_2();
- else if (function == 16)
+ playTalkSequence(function);
+
+ if (currentChapter == 2) {
+ if (function == 16)
animation_16_2();
- else if (function == 17)
- animation_17_2();
- else if (function == 19)
- animation_19_2();
else if (function == 20)
animation_20_2();
- else if (function == 21)
- animation_21_2();
else if (function == 23)
animation_23_2();
- else if (function == 28)
- animation_28_2();
else if (function == 29)
animation_29_2();
- else if (function == 30)
- animation_30_2();
else if (function == 31)
animation_31_2();
- } else if (currentChapter == 4) {
- if (function == 2)
- animation_2_4();
- else if (function == 3)
- animation_3_4();
- else if (function == 4)
- animation_4_4();
- } else if (currentChapter == 5) {
- if (function == 2)
- animation_2_5();
- else if (function == 3)
- animation_3_5();
- else if (function == 6)
- animation_6_5();
- else if (function == 7)
- animation_7_5();
- else if (function == 8)
- animation_8_5();
- else if (function == 15)
- animation_15_5();
- else if (function == 16)
- animation_16_5();
- else if (function == 17)
- animation_17_5();
- } else if (currentChapter == 6) {
- if (function == 2)
- animation_2_6();
- else if (function == 3)
- animation_3_6();
- else if (function == 4)
- animation_4_6();
- else if (function == 11)
- animation_11_6();
- else if (function == 12)
- animation_12_6();
- else if (function == 13)
- animation_13_6();
- else if (function == 14)
- animation_14_6();
- else if (function == 15)
- animation_15_6();
+ } else if (currentChapter == 3) {
+ grr();
}
}
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index a426857fbd..81c8d9a62a 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -195,6 +195,38 @@ static const DrasculaGameDescription gameDescriptions[] = {
},
},
+ {
+ // Drascula Spanish version (ScummVM repacked files)
+ {
+ "drascula",
+ 0,
+ {
+ {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563},
+ {"packet.004", 0, "a289d3cf80d50f25ec569b653248437e", 17205838},
+ {NULL, 0, NULL, 0}
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ GF_PACKED
+ },
+ },
+
+ {
+ // Drascula Italian version (ScummVM repacked files)
+ {
+ "drascula",
+ 0,
+ {
+ {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563},
+ {"packet.005", 0, "58caac54b891f5d7f335e710e45e5d29", 16209623},
+ {NULL, 0, NULL, 0}
+ },
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ GF_PACKED
+ },
+ },
+
{ AD_TABLE_END_MARKER }
};
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 1cbe2ae0e1..c1449ea2c9 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -65,7 +65,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
if (cd_num >= 0)
_system->openCD(cd_num);
- _lang = 0;
+ _lang = kEnglish;
}
DrasculaEngine::~DrasculaEngine() {
@@ -86,6 +86,7 @@ DrasculaEngine::~DrasculaEngine() {
free(_roomPreUpdates);
free(_roomUpdates);
free(_roomActions);
+ free(_talkSequences);
freeTexts(_text);
freeTexts(_textd);
freeTexts(_textb);
@@ -112,23 +113,23 @@ int DrasculaEngine::init() {
switch (getLanguage()) {
case Common::EN_ANY:
- _lang = 0;
+ _lang = kEnglish;
break;
case Common::ES_ESP:
- _lang = 1;
+ _lang = kSpanish;
break;
case Common::DE_DEU:
- _lang = 2;
+ _lang = kGerman;
break;
case Common::FR_FRA:
- _lang = 3;
+ _lang = kFrench;
break;
case Common::IT_ITA:
- _lang = 4;
+ _lang = kItalian;
break;
default:
warning("Unknown game language. Falling back to English");
- _lang = 0;
+ _lang = kEnglish;
}
_charMap = 0;
@@ -162,6 +163,12 @@ int DrasculaEngine::init() {
_textmisc = 0;
_textd1 = 0;
+ _color = 0;
+ blinking = 0;
+ leftMouseButton = 0;
+ rightMouseButton = 0;
+ *textName = 0;
+
if (!loadDrasculaDat())
return 1;
@@ -173,7 +180,9 @@ int DrasculaEngine::init() {
int DrasculaEngine::go() {
currentChapter = 1; // values from 1 to 6 will start each part of game
- hay_que_load = 0;
+ loadedDifferentChapter = 0;
+
+ checkCD();
for (;;) {
int i;
@@ -193,7 +202,6 @@ int DrasculaEngine::go() {
talkHeight = TALK_HEIGHT; talkWidth = TALK_WIDTH;
hasAnswer = 0;
savedTime = 0;
- changeColor = 0;
breakOut = 0;
vonBraunX = 120; trackVonBraun = 1; vonBraunHasMoved = 0;
framesWithoutAction = 0;
@@ -215,50 +223,46 @@ int DrasculaEngine::go() {
withVoices = 0;
selectionMade = 0;
- if (currentChapter != 6)
- loadPic(95, tableSurface);
+ if (currentChapter != 3)
+ loadPic(96, frontSurface, COMPLETE_PAL);
if (currentChapter == 1) {
- loadPic(96, frontSurface, COMPLETE_PAL);
- loadPic(99, backSurface);
- loadPic(97, extraSurface);
} else if (currentChapter == 2) {
- loadPic(96, frontSurface, COMPLETE_PAL);
loadPic("pts.alg", drawSurface2);
} else if (currentChapter == 3) {
loadPic("aux13.alg", bgSurface, COMPLETE_PAL);
loadPic(96, frontSurface);
- loadPic(97, extraSurface);
- loadPic(99, backSurface);
} else if (currentChapter == 4) {
- loadPic(96, frontSurface, COMPLETE_PAL);
- if (hay_que_load == 0)
+ if (loadedDifferentChapter == 0)
animation_ray();
loadPic(96, frontSurface);
clearRoom();
- loadPic(99, backSurface);
- loadPic(97, extraSurface);
} else if (currentChapter == 5) {
- loadPic(96, frontSurface, COMPLETE_PAL);
- loadPic(97, extraSurface);
- loadPic(99, backSurface);
} else if (currentChapter == 6) {
igorX = 105, igorY = 85, trackIgor = 1;
drasculaX = 62, drasculaY = 99, trackDrascula = 1;
actorFrames[kFramePendulum] = 0;
flag_tv = 0;
+ }
- loadPic(96, frontSurface, COMPLETE_PAL);
+ loadPic(95, tableSurface);
+ for (i = 0; i < 25; i++)
+ memcpy(crosshairCursor + i * 40, tableSurface + 225 + (56 + i) * 320, 40);
+
+ if (_lang == kSpanish)
+ loadPic(974, tableSurface);
+
+ if (currentChapter != 2) {
loadPic(99, backSurface);
loadPic(97, extraSurface);
- loadPic(95, tableSurface);
}
+
memset(iconName, 0, sizeof(iconName));
for (i = 0; i < 6; i++)
- strcpy(iconName[i + 1], _textverbs[_lang][i]);
+ strcpy(iconName[i + 1], _textverbs[i]);
- assignDefaultPalette();
+ assignPalette(defaultPalette);
if (!runCurrentChapter()) {
endChapter();
break;
@@ -286,10 +290,7 @@ void DrasculaEngine::endChapter() {
bool DrasculaEngine::runCurrentChapter() {
int n;
- if (_lang == kSpanish)
- textSurface = extraSurface;
- else
- textSurface = tableSurface;
+ rightMouseButton = 0;
previousMusic = -1;
@@ -319,14 +320,14 @@ bool DrasculaEngine::runCurrentChapter() {
if (currentChapter == 1) {
pickObject(28);
- if (hay_que_load == 0)
+ if (loadedDifferentChapter == 0)
animation_1_1();
- withoutVerb();
+ selectVerb(0);
loadPic("2aux62.alg", drawSurface2);
trackProtagonist = 1;
objExit = 104;
- if (hay_que_load != 0) {
+ if (loadedDifferentChapter != 0) {
if (!loadGame(saveName)) {
return true;
}
@@ -340,7 +341,7 @@ bool DrasculaEngine::runCurrentChapter() {
addObject(kItemPhone);
trackProtagonist = 3;
objExit = 162;
- if (hay_que_load == 0)
+ if (loadedDifferentChapter == 0)
enterRoom(14);
else {
if (!loadGame(saveName)) {
@@ -358,7 +359,7 @@ bool DrasculaEngine::runCurrentChapter() {
flags[1] = 1;
trackProtagonist = 1;
objExit = 99;
- if (hay_que_load == 0)
+ if (loadedDifferentChapter == 0)
enterRoom(20);
else {
if (!loadGame(saveName)) {
@@ -372,7 +373,7 @@ bool DrasculaEngine::runCurrentChapter() {
addObject(kItemReefer2);
addObject(kItemOneCoin2);
objExit = 100;
- if (hay_que_load == 0) {
+ if (loadedDifferentChapter == 0) {
enterRoom(21);
trackProtagonist = 0;
curX = 235;
@@ -394,7 +395,7 @@ bool DrasculaEngine::runCurrentChapter() {
addObject(20);
trackProtagonist = 1;
objExit = 100;
- if (hay_que_load == 0) {
+ if (loadedDifferentChapter == 0) {
enterRoom(45);
} else {
if (!loadGame(saveName)) {
@@ -407,7 +408,7 @@ bool DrasculaEngine::runCurrentChapter() {
trackProtagonist = 1;
objExit = 104;
- if (hay_que_load == 0) {
+ if (loadedDifferentChapter == 0) {
enterRoom(58);
animation_1_6();
} else {
@@ -418,6 +419,8 @@ bool DrasculaEngine::runCurrentChapter() {
}
}
+ showCursor();
+
while (1) {
if (characterMoved == 0) {
stepX = STEP_X;
@@ -436,7 +439,8 @@ bool DrasculaEngine::runCurrentChapter() {
// made the character start walking off screen, as his actual position was
// different than the displayed one
if (roomNumber == 3 && (curX == 279) && (curY + curHeight == 101)) {
- animation_1_2();
+ gotoObject(178, 121);
+ gotoObject(169, 135);
} else if (roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) {
walkToObject = 1;
gotoObject(190, 130);
@@ -457,12 +461,26 @@ bool DrasculaEngine::runCurrentChapter() {
playMusic(roomMusic);
}
+ delay(25);
+#ifndef _WIN32_WCE
+ // FIXME
+ // This and the following #ifndefs disable the excess updateEvents() calls *within* the game loop.
+ // Events such as keypresses or mouse clicks are dropped on the ground with no processing
+ // by these calls. They are properly handled by the implicit call through getScan() below.
+ // It is not a good practice to not process events and indeed this created problems with synthesized
+ // events in the wince port.
updateEvents();
+#endif
if (menuScreen == 0 && takeObject == 1)
checkObjects();
+#ifdef _WIN32_WCE
+ if (rightMouseButton)
+ if (menuScreen) {
+#else
if (rightMouseButton == 1 && menuScreen == 1) {
+#endif
delay(100);
if (currentChapter == 2)
loadPic(menuBackground, backSurface);
@@ -470,9 +488,24 @@ bool DrasculaEngine::runCurrentChapter() {
loadPic(99, backSurface);
setPalette((byte *)&gamePalette);
menuScreen = 0;
+#ifndef _WIN32_WCE
+ // FIXME: This call here is in hope that it will catch the rightmouseup event so the
+ // next if block won't be executed. This too is not a good coding practice. I've recoded it
+ // with a mutual exclusive if block for the menu. I would commit this properly but I cannot test
+ // for other (see Desktop) ports right now.
updateEvents();
+#endif
+#ifdef _WIN32_WCE
+ } else {
+#else
}
- if (rightMouseButton == 1 && menuScreen == 0) {
+
+ // Do not show the inventory screen in chapter 5, if the right mouse button is clicked
+ // while the plug (object 16) is held
+ // Fixes bug #2059621 - "DRASCULA: Plug bug"
+ if (rightMouseButton == 1 && menuScreen == 0 &&
+ !(currentChapter == 5 && pickedObject == 16)) {
+#endif
delay(100);
characterMoved = 0;
if (trackProtagonist == 2)
@@ -486,8 +519,10 @@ bool DrasculaEngine::runCurrentChapter() {
else
loadPic("icons.alg", backSurface);
menuScreen = 1;
+#ifndef _WIN32_WCE
updateEvents();
- withoutVerb();
+#endif
+ selectVerb(0);
}
if (leftMouseButton == 1 && menuBar == 1) {
@@ -523,15 +558,15 @@ bool DrasculaEngine::runCurrentChapter() {
if (!saveLoadScreen())
return true;
} else if (key == Common::KEYCODE_F8) {
- withoutVerb();
+ selectVerb(0);
} else if (key == Common::KEYCODE_v) {
withVoices = 1;
- print_abc(_textsys[_lang][2], 96, 86);
+ print_abc(_textsys[2], 96, 86);
updateScreen();
delay(1410);
} else if (key == Common::KEYCODE_t) {
withVoices = 0;
- print_abc(_textsys[_lang][3], 94, 86);
+ print_abc(_textsys[3], 94, 86);
updateScreen();
delay(1460);
} else if (key == Common::KEYCODE_ESCAPE) {
@@ -563,8 +598,10 @@ char *DrasculaEngine::getLine(char *buf, int len) {
for (;;) {
b = buf;
- while (!_arj.eos()) {
+ while (true) {
c = ~_arj.readByte();
+ if (_arj.eos()) break;
+
if (c == '\r')
continue;
if (c == '\n' || b - buf >= (len - 1))
@@ -672,10 +709,14 @@ void DrasculaEngine::updateEvents() {
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
- AudioCD.updateCD();
+ updateMusic();
+#ifdef _WIN32_WCE
+ if (eventMan->pollEvent(event)) {
+#else
while (eventMan->pollEvent(event)) {
- switch (event.type) {
+#endif
+ switch (event.type) {
case Common::EVENT_KEYDOWN:
_keyPressed = event.kbd;
break;
@@ -725,7 +766,6 @@ void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int w
float totalX, totalY;
int n, m;
float pixelX, pixelY;
- int pixelPos[6];
newWidth = (width * factor) / 100;
newHeight = (height * factor) / 100;
@@ -738,14 +778,8 @@ void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int w
for (n = 0; n < newHeight; n++) {
for (m = 0; m < newWidth; m++) {
- pixelPos[0] = (int)pixelX;
- pixelPos[1] = (int)pixelY;
- pixelPos[2] = xx2 + m;
- pixelPos[3] = yy2 + n;
- pixelPos[4] = 1;
- pixelPos[5] = 1;
-
- copyRectClip(pixelPos, dir_inicio, dir_fin);
+ copyRect((int)pixelX, (int)pixelY, xx2 + m, yy2 + n,
+ 1, 1, dir_inicio, dir_fin);
pixelX += totalX;
}
@@ -762,7 +796,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){
do {
counter--;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
if (currentChapter == 3)
updateScreen(0, 0, 0, y, 320, 200, screenSurface);
else
@@ -786,7 +820,7 @@ void DrasculaEngine::hipo_sin_nadie(int counter){
}
} while (counter > 0);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
}
@@ -931,6 +965,15 @@ bool DrasculaEngine::loadDrasculaDat() {
_roomActions[i].speechID = in.readSint16BE();
}
+ _talkSequencesSize = in.readUint16BE();
+ _talkSequences = (TalkSequenceCommand *)malloc(sizeof(TalkSequenceCommand) * _talkSequencesSize);
+ for (i = 0; i < _talkSequencesSize; i++) {
+ _talkSequences[i].chapter = in.readSint16BE();
+ _talkSequences[i].sequence = in.readSint16BE();
+ _talkSequences[i].commandType = in.readSint16BE();
+ _talkSequences[i].action = in.readSint16BE();
+ }
+
_numLangs = in.readUint16BE();
_text = loadTexts(in);
@@ -952,24 +995,22 @@ bool DrasculaEngine::loadDrasculaDat() {
return true;
}
-char ***DrasculaEngine::loadTexts(Common::File &in) {
+char **DrasculaEngine::loadTexts(Common::File &in) {
int numTexts = in.readUint16BE();
- char ***res;
+ char **res = (char **)malloc(sizeof(char *) * numTexts);
int entryLen;
- char *pos;
+ char *pos = 0;
int len;
- res = (char ***)malloc(sizeof(char *) * _numLangs);
-
for (int lang = 0; lang < _numLangs; lang++) {
entryLen = in.readUint16BE();
-
- res[lang] = (char **)malloc(sizeof(char *) * numTexts);
-
pos = (char *)malloc(entryLen);
- res[lang][0] = pos;
-
- in.read(res[lang][0], entryLen);
+ if (lang == _lang) {
+ res[0] = pos;
+ in.read(res[0], entryLen);
+ } else {
+ in.read(pos, entryLen);
+ }
pos += DATAALIGNMENT;
@@ -979,18 +1020,19 @@ char ***DrasculaEngine::loadTexts(Common::File &in) {
len = READ_BE_UINT16(pos);
pos += 2 + len;
- res[lang][i] = pos;
+ if (lang == _lang)
+ res[i] = pos;
}
}
return res;
}
-void DrasculaEngine::freeTexts(char ***ptr) {
- for (int lang = 0; lang < _numLangs; lang++) {
- free(ptr[lang][0] - DATAALIGNMENT);
- free(ptr[lang]);
- }
+void DrasculaEngine::freeTexts(char **ptr) {
+ if (!ptr)
+ return;
+
+ free(ptr[0]);
free(ptr);
}
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index 8bb73d8dd1..3b499f27a0 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -37,16 +37,13 @@
#include "common/keyboard.h"
#include "common/unarj.h"
-#include "sound/audiostream.h"
#include "sound/mixer.h"
-#include "sound/voc.h"
-#include "sound/audiocd.h"
#include "engines/engine.h"
namespace Drascula {
-#define DRASCULA_DAT_VER 2
+#define DRASCULA_DAT_VER 4
#define DATAALIGNMENT 4
enum DrasculaGameFeatures {
@@ -135,6 +132,11 @@ enum IgorTalkerTypes {
kIgorWig = 4
};
+enum VonBraunTalkerTypes {
+ kVonBraunNormal = 0,
+ kVonBraunDoor = 1
+};
+
enum AnimFrameTypes {
kFrameBlind = 0,
kFrameSnore = 1,
@@ -146,6 +148,64 @@ enum AnimFrameTypes {
kFramePendulum = 7
};
+enum DialogOptionStatus {
+ kDialogOptionUnselected = 1,
+ kDialogOptionSelected = 2,
+ kDialogOptionClicked = 3
+};
+
+enum TalkSequenceCommands {
+ kPause = 0,
+ kSetFlag = 1,
+ kClearFlag = 2,
+ kPickObject = 3,
+ kAddObject = 4,
+ kBreakOut = 5,
+ kConverse = 6,
+ kPlaceVB = 7,
+ kUpdateRoom = 8,
+ kUpdateScreen = 9,
+ kTrackProtagonist = 10,
+ kPlaySound = 11,
+ kFinishSound = 12,
+ kTalkerGeneral = 13,
+ kTalkerDrunk = 14,
+ kTalkerPianist = 15,
+ kTalkerBJ = 16,
+ kTalkerVBNormal = 17,
+ kTalkerVBDoor = 18,
+ kTalkerIgorSeated = 19,
+ kTalkerWerewolf = 20,
+ kTalkerMus = 21,
+ kTalkerDrascula = 22,
+ kTalkerBartender0 = 23,
+ kTalkerBartender1 = 24
+};
+
+enum CharacterDirections {
+ kDirectionUp = 0,
+ kDirectionDown = 1,
+ kDirectionLeft = 2,
+ kDirectionRight = 3
+};
+
+enum MouseCursors {
+ kCursorCrosshair = 0,
+ kCursorCurrentItem = 1
+};
+
+enum DoorActions {
+ kCloseDoor = 0,
+ kOpenDoor = 1
+};
+
+struct TalkSequenceCommand {
+ int chapter;
+ int sequence;
+ int commandType;
+ int action;
+};
+
#define TEXTD_START 68
struct DrasculaGameDescription;
@@ -248,13 +308,18 @@ public:
typedef signed char DacPalette256[256][3];
void setRGB(byte *pal, int plt);
- void assignDefaultPalette();
+ void assignPalette(DacPalette256 pal);
+ void setDefaultPalette(DacPalette256 pal);
void setPalette(byte *PalBuf);
void copyBackground(int xorg, int yorg, int xdes, int ydes, int width,
int height, byte *src, byte *dest);
+
+ void copyBackground() {
+ copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ }
+
void copyRect(int xorg, int yorg, int xdes, int ydes, int width,
int height, byte *src, byte *dest);
- void copyRectClip(int *Array, byte *src, byte *dest);
void updateScreen() {
updateScreen(0, 0, 0, 0, 320, 200, screenSurface);
}
@@ -275,6 +340,9 @@ public:
DacPalette256 brightPalette;
DacPalette256 darkPalette;
+ byte *crosshairCursor;
+ byte *mouseCursor;
+
// Graphics buffers/pointers
byte *VGA;
byte *bgSurface;
@@ -309,7 +377,7 @@ public:
int roomObjX[40], roomObjY[40], trackObj[40];
int inventoryObjects[43];
char _targetSurface[40][20];
- int _destX[40], _destY[40], trackCharacter_alkeva[40], alapuertakeva[40];
+ int _destX[40], _destY[40], trackCharacter_alkeva[40], roomExits[40];
int x1[40], y1[40], x2[40], y2[40];
int takeObject, pickedObject;
int withVoices;
@@ -321,7 +389,8 @@ public:
int flags[NUM_FLAGS];
int frame_y;
- int curX, curY, characterMoved, curDirection, trackProtagonist, num_frame, hare_se_ve;
+ int curX, curY, characterMoved, curDirection, trackProtagonist, num_frame;
+ int hare_se_ve; // TODO: what is this for?
int roomX, roomY, checkFlags;
int doBreak;
int stepX, stepY;
@@ -334,7 +403,6 @@ public:
int timeDiff, startTime;
int hasAnswer;
int savedTime;
- int changeColor;
int breakOut;
int vonBraunX, trackVonBraun, vonBraunHasMoved;
float newHeight, newWidth;
@@ -347,7 +415,7 @@ public:
int framesWithoutAction;
int term_int;
int currentChapter;
- int hay_que_load;
+ int loadedDifferentChapter;
char saveName[13];
int _color;
int musicStopped;
@@ -368,12 +436,9 @@ public:
void moveVonBraun();
void placeVonBraun(int pointX);
void hipo_sin_nadie(int counter);
- void openDoor(int nflag, int doorNum);
+ void toggleDoor(int nflag, int doorNum, int action);
void showMap();
- void setDarkPalette();
-
- void withoutVerb();
void enterRoom(int);
void clearRoom();
void gotoObject(int, int);
@@ -399,6 +464,7 @@ public:
void fadeToBlack(int fadeSpeed);
signed char adjustToVGA(signed char value);
void color_abc(int cl);
+ bool textFitsCentered(char *text, int x);
void centerText(const char *,int,int);
void playSound(int soundNum);
bool animate(const char *animation, int FPS);
@@ -408,7 +474,7 @@ public:
void placeDrascula();
void talkInit(const char *filename);
- bool isTalkFinished(int* length);
+ bool isTalkFinished();
void talk_igor(int, int);
void talk_drascula(int index, int talkerType = 0);
void talk_solo(const char *, const char *);
@@ -417,7 +483,7 @@ public:
void talk_bj_bed(int);
void talk_htel(int);
void talk_bj(int);
- void talk_baul(int);
+ void talk_trunk(int);
void talk(int);
void talk(const char *, const char *);
void talk_sync(const char *, const char *, const char *);
@@ -425,9 +491,8 @@ public:
void talk_pianist(int);
void talk_werewolf(int);
void talk_mus(int);
- void talk_dr_grande(int);
- void talk_vonBraun(int);
- void talk_vonBraunpuerta(int);
+ void talk_drascula_big(int);
+ void talk_vonBraun(int, int);
void talk_blind(int);
void talk_hacker(int);
void talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface);
@@ -435,18 +500,14 @@ public:
void hiccup(int);
void finishSound();
void stopSound();
- void closeDoor(int nflag, int doorNum);
void playMusic(int p);
void stopMusic();
+ void updateMusic();
int musicStatus();
void updateRoom();
bool loadGame(const char *);
void updateDoor(int);
- void setDefaultPalette();
void setPaletteBase(int darkness);
- void assignBrightPalette();
- void assignDarkPalette();
- void setBrightPalette();
void updateVisible();
void startWalking();
void updateRefresh();
@@ -458,7 +519,10 @@ public:
bool exitRoom(int);
bool pickupObject();
bool checkAction(int);
- void setCursorTable();
+ void setCursor(int cursor);
+ void showCursor();
+ void hideCursor();
+ bool isCursorVisible();
void enterName();
bool soundIsActive();
void waitFrameSSN();
@@ -490,8 +554,11 @@ public:
bool checkMenuFlags();
void setupRoomsTable();
bool roomParse(int, int);
+ void cleanupString(char *string);
+ void playTalkSequence(int sequence);
+ void doTalkSequenceCommand(TalkSequenceCommand cmd);
void converse(int);
- void print_abc_opc(const char *, int, int, int);
+ void print_abc_opc(const char *, int, int);
void response(int);
void activatePendulum();
@@ -551,28 +618,17 @@ public:
void animation_3_1();
void animation_4_1();
//
- void animation_1_2();
void animation_2_2();
- void animation_3_2();
void animation_4_2();
void animation_5_2();
void animation_6_2();
void animation_7_2();
- void animation_8_2();
- void animation_9_2();
- void animation_10_2();
void animation_11_2();
void animation_12_2();
void animation_13_2();
void animation_14_2();
- void animation_15_2();
void animation_16_2();
- void animation_17_2();
- void animation_18_2();
- void animation_19_2();
void animation_20_2();
- void animation_21_2();
- void animation_22_2();
void animation_23_2();
void animation_23_joined();
void animation_23_joined2();
@@ -580,9 +636,7 @@ public:
void animation_25_2();
void animation_26_2();
void animation_27_2();
- void animation_28_2();
void animation_29_2();
- void animation_30_2();
void animation_31_2();
void animation_32_2();
void animation_33_2();
@@ -590,7 +644,6 @@ public:
void animation_35_2();
void animation_36_2();
//
- void animation_1_3();
void animation_2_3();
void animation_3_3();
void animation_4_3();
@@ -599,48 +652,22 @@ public:
void animation_ray();
//
void animation_1_4();
- void animation_2_4();
- void animation_3_4();
- void animation_4_4();
void animation_5_4();
void animation_6_4();
void animation_7_4();
void animation_8_4();
- void animation_9_4();
//
void animation_1_5();
- void animation_2_5();
- void animation_3_5();
- void animation_4_5();
void animation_5_5();
- void animation_6_5();
- void animation_7_5();
- void animation_8_5();
- void animation_9_5();
- void animation_10_5();
void animation_11_5();
void animation_12_5();
void animation_13_5();
void animation_14_5();
- void animation_15_5();
- void animation_16_5();
- void animation_17_5();
//
void animation_1_6();
- void animation_2_6();
- void animation_3_6();
- void animation_4_6();
void animation_5_6();
void animation_6_6();
- void animation_7_6();
void animation_9_6();
- void animation_10_6();
- void animation_11_6();
- void animation_12_6();
- void animation_13_6();
- void animation_14_6();
- void animation_15_6();
- void animation_18_6();
void animation_19_6();
void update_1_pre();
@@ -683,23 +710,24 @@ private:
int _roomPreUpdatesSize;
int _roomUpdatesSize;
int _roomActionsSize;
+ int _talkSequencesSize;
int _numLangs;
- char ***_text;
- char ***_textd;
- char ***_textb;
- char ***_textbj;
- char ***_texte;
- char ***_texti;
- char ***_textl;
- char ***_textp;
- char ***_textt;
- char ***_textvb;
- char ***_textsys;
- char ***_texthis;
- char ***_textverbs;
- char ***_textmisc;
- char ***_textd1;
+ char **_text;
+ char **_textd;
+ char **_textb;
+ char **_textbj;
+ char **_texte;
+ char **_texti;
+ char **_textl;
+ char **_textp;
+ char **_textt;
+ char **_textvb;
+ char **_textsys;
+ char **_texthis;
+ char **_textverbs;
+ char **_textmisc;
+ char **_textd1;
ItemLocation *_itemLocations;
int *_polX, *_polY;
int *_verbBarX;
@@ -709,9 +737,10 @@ private:
int *_pianistX, *_drunkX;
RoomUpdate *_roomPreUpdates, *_roomUpdates;
RoomTalkAction *_roomActions;
+ TalkSequenceCommand *_talkSequences;
- char ***loadTexts(Common::File &in);
- void freeTexts(char ***ptr);
+ char **loadTexts(Common::File &in);
+ void freeTexts(char **ptr);
};
} // End of namespace Drascula
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp
index 67993bfb6c..de35de5ab2 100644
--- a/engines/drascula/graphics.cpp
+++ b/engines/drascula/graphics.cpp
@@ -47,6 +47,10 @@ void DrasculaEngine::allocMemory() {
assert(tableSurface);
extraSurface = (byte *)malloc(64000);
assert(extraSurface);
+ crosshairCursor = (byte *)malloc(40 * 25);
+ assert(crosshairCursor);
+ mouseCursor = (byte *)malloc(OBJWIDTH * OBJHEIGHT);
+ assert(mouseCursor);
}
void DrasculaEngine::freeMemory() {
@@ -58,10 +62,12 @@ void DrasculaEngine::freeMemory() {
free(drawSurface3);
free(extraSurface);
free(frontSurface);
+ free(crosshairCursor);
+ free(mouseCursor);
}
void DrasculaEngine::moveCursor() {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
moveCharacters();
@@ -78,14 +84,6 @@ void DrasculaEngine::moveCursor() {
showMenu();
else if (menuBar == 1)
clearMenu();
-
- int cursorPos[6] = { 0, 0, mouseX - 20, mouseY - 17, OBJWIDTH, OBJHEIGHT };
- copyRectClip(cursorPos, drawSurface3, screenSurface);
-}
-
-void DrasculaEngine::setCursorTable() {
- int cursorPos[6] = { 225, 56, mouseX - 20, mouseY - 12, 40, 25 };
- copyRectClip(cursorPos, tableSurface, screenSurface);
}
void DrasculaEngine::loadPic(const char *NamePcc, byte *targetSurface, int colorCount) {
@@ -148,7 +146,15 @@ void DrasculaEngine::copyBackground(int xorg, int yorg, int xdes, int ydes, int
int height, byte *src, byte *dest) {
dest += xdes + ydes * 320;
src += xorg + yorg * 320;
+ /* Unoptimized code
for (int x = 0; x < height; x++) {
+ memcpy(dest + 320 * x, src + 320 * x, width);
+ } */
+
+ // A bit more optimized code, thanks to Fingolfin
+ // Uses 2 less registers and performs 2 less multiplications
+ int x = height;
+ while (x--) {
memcpy(dest, src, width);
dest += 320;
src += 320;
@@ -159,24 +165,7 @@ void DrasculaEngine::copyRect(int xorg, int yorg, int xdes, int ydes, int width,
int height, byte *src, byte *dest) {
int y, x;
- dest += xdes + ydes * 320;
- src += xorg + yorg * 320;
-
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- if (src[x + y * 320] != 255)
- dest[x + y * 320] = src[x + y * 320];
-}
-
-void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) {
- int y, x;
- int xorg = Array[0];
- int yorg = Array[1];
- int xdes = Array[2];
- int ydes = Array[3];
- int width = Array[4];
- int height = Array[5];
-
+ //
if (ydes < 0) {
yorg += -ydes;
height += ydes;
@@ -191,6 +180,7 @@ void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) {
width -= (xdes + width) - 320;
if ((ydes + height) > 199)
height -= (ydes + height) - 200;
+ //
dest += xdes + ydes * 320;
src += xorg + yorg * 320;
@@ -202,16 +192,7 @@ void DrasculaEngine::copyRectClip(int *Array, byte *src, byte *dest) {
}
void DrasculaEngine::updateScreen(int xorg, int yorg, int xdes, int ydes, int width, int height, byte *buffer) {
- byte *ptr = VGA;
-
- ptr += xdes + ydes * 320;
- buffer += xorg + yorg * 320;
- for (int x = 0; x < height; x++) {
- memcpy(ptr, buffer, width);
- ptr += 320;
- buffer += 320;
- }
-
+ copyBackground(xorg, yorg, xdes, ydes, width, height, buffer, VGA);
_system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200);
_system->updateScreen();
}
@@ -229,22 +210,22 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
letterX = _charMap[i].mappedChar;
switch (_charMap[i].charType) {
- case 0: // letters
- letterY = (_lang == kSpanish) ? 149 : 158;
- break;
- case 1: // signs
- letterY = (_lang == kSpanish) ? 160 : 169;
- break;
- case 2: // accented
- letterY = 180;
- break;
+ case 0: // letters
+ letterY = (_lang == kSpanish) ? 149 : 158;
+ break;
+ case 1: // signs
+ letterY = (_lang == kSpanish) ? 160 : 169;
+ break;
+ case 2: // accented
+ letterY = 180;
+ break;
} // switch
break;
} // if
} // for
- int textPos[6] = { letterX, letterY, screenX, screenY, CHAR_WIDTH, CHAR_HEIGHT };
- copyRectClip(textPos, textSurface, screenSurface);
+ copyRect(letterX, letterY, screenX, screenY,
+ CHAR_WIDTH, CHAR_HEIGHT, tableSurface, screenSurface);
screenX = screenX + CHAR_WIDTH;
if (screenX > 317) {
@@ -254,10 +235,12 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
} // for
}
-void DrasculaEngine::print_abc_opc(const char *said, int screenX, int screenY, int game) {
+void DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) {
int signY, letterY, letterX = 0;
uint len = strlen(said);
+ int screenX = 1;
+
for (uint h = 0; h < len; h++) {
if (game == 1) {
letterY = 6;
@@ -293,76 +276,70 @@ void DrasculaEngine::print_abc_opc(const char *said, int screenX, int screenY, i
} // if
} // for
- int textPos[6] = { letterX, letterY, screenX, screenY, CHAR_WIDTH_OPC, CHAR_HEIGHT_OPC };
- copyRectClip(textPos, backSurface, screenSurface);
+ copyRect(letterX, letterY, screenX, screenY,
+ CHAR_WIDTH_OPC, CHAR_HEIGHT_OPC, backSurface, screenSurface);
screenX = screenX + CHAR_WIDTH_OPC;
}
}
-void DrasculaEngine::centerText(const char *message, int textX, int textY) {
- char bb[200], m2[200], m1[200], mb[10][50];
- char m3[200];
- int h, fil, textX3, textX2, textX1, conta_f = 0, ya = 0;
-
- strcpy(m1, " ");
- strcpy(m2, " ");
- strcpy(m3, " ");
- strcpy(bb, " ");
-
- for (h = 0; h < 10; h++)
- strcpy(mb[h], " ");
-
- if (textX > 160)
- ya = 1;
-
- strcpy(m1, message);
- textX = CLIP<int>(textX, 60, 255);
-
- textX1 = textX;
-
- if (ya == 1)
- textX1 = 315 - textX;
-
- textX2 = (strlen(m1) / 2) * CHAR_WIDTH;
-
- while (true) {
- strcpy(bb, m1);
- scumm_strrev(bb);
-
- if (textX1 < textX2) {
- strcpy(m3, strrchr(m1, ' '));
- strcpy(m1, strstr(bb, " "));
- scumm_strrev(m1);
- m1[strlen(m1) - 1] = '\0';
- strcat(m3, m2);
- strcpy(m2, m3);
- };
-
- textX2 = (strlen(m1) / 2) * CHAR_WIDTH;
-
- if (textX1 < textX2)
- continue;
+bool DrasculaEngine::textFitsCentered(char *text, int x) {
+ int len = strlen(text);
+ int tmp = CLIP<int>(x - len * CHAR_WIDTH / 2, 60, 255);
+ return (tmp + len * CHAR_WIDTH) <= 320;
+}
- strcpy(mb[conta_f], m1);
+void DrasculaEngine::centerText(const char *message, int textX, int textY) {
+ char msg[200];
+ char messageLine[200];
+ char tmpMessageLine[200];
+ *messageLine = 0;
+ *tmpMessageLine = 0;
+ char *curWord;
+ int curLine = 0;
+ int x = 0;
+ // original starts printing 4 lines above textY
+ int y = CLIP<int>(textY - (4 * CHAR_HEIGHT), 0, 320);
- if (!strcmp(m2, ""))
- break;
+ strcpy(msg, message);
- scumm_strrev(m2);
- m2[strlen(m2) - 1] = '\0';
- scumm_strrev(m2);
- strcpy(m1, m2);
- strcpy(m2, "");
- conta_f++;
+ // If the message fits on screen as-is, just print it here
+ if (textFitsCentered(msg, textX)) {
+ x = CLIP<int>(textX - strlen(msg) * CHAR_WIDTH / 2, 60, 255);
+ print_abc(msg, x, y);
+ return;
}
- fil = textY - (((conta_f + 3) * CHAR_HEIGHT));
+ // Message doesn't fit on screen, split it
+
+ // Get a word from the message
+ curWord = strtok(msg, " ");
+ while (curWord != NULL) {
+ // Check if the word and the current line fit on screen
+ if (strlen(tmpMessageLine) > 0)
+ strcat(tmpMessageLine, " ");
+ strcat(tmpMessageLine, curWord);
+ if (textFitsCentered(tmpMessageLine, textX)) {
+ // Line fits, so add the word to the current message line
+ strcpy(messageLine, tmpMessageLine);
+ } else {
+ // Line doesn't fit, so show the current line on screen and
+ // create a new one
+ // If it goes off screen, print_abc will adjust it
+ x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255);
+ print_abc(messageLine, x, y + curLine * CHAR_HEIGHT);
+ strcpy(messageLine, curWord);
+ strcpy(tmpMessageLine, curWord);
+ curLine++;
+ }
+
+ // Get next word
+ curWord = strtok(NULL, " ");
- for (h = 0; h < conta_f + 1; h++) {
- textX3 = strlen(mb[h]) / 2;
- print_abc(mb[h], ((textX) - textX3 * CHAR_WIDTH) - 1, fil);
- fil = fil + CHAR_HEIGHT + 2;
+ if (curWord == NULL) {
+ x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255);
+ print_abc(messageLine, x, y + curLine * CHAR_HEIGHT);
+ }
}
}
@@ -375,6 +352,8 @@ void DrasculaEngine::screenSaver() {
int tempLine[320];
int tempRow[200];
+ hideCursor();
+
clearRoom();
loadPic("sv.alg", bgSurface, HALF_PAL);
@@ -463,6 +442,7 @@ void DrasculaEngine::screenSaver() {
free(ghost);
loadPic(roomNumber, bgSurface, HALF_PAL);
+ showCursor();
}
void DrasculaEngine::playFLI(const char *filefli, int vel) {
@@ -621,12 +601,11 @@ void DrasculaEngine::decodeRLE(byte* srcPtr, byte* dstPtr) {
pixel = *srcPtr++;
}
for (uint j = 0; j < repeat; j++) {
- curByte++;
- if (curByte > 64000) {
+ *dstPtr++ = pixel;
+ if (++curByte >= 64000) {
stopProcessing = true;
break;
}
- *dstPtr++ = pixel;
}
}
}
diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp
index 6e86788007..32f07fce73 100644
--- a/engines/drascula/interface.cpp
+++ b/engines/drascula/interface.cpp
@@ -24,9 +24,34 @@
*/
#include "drascula/drascula.h"
+#include "graphics/cursorman.h"
namespace Drascula {
+void DrasculaEngine::setCursor(int cursor) {
+ switch (cursor) {
+ case kCursorCrosshair:
+ CursorMan.replaceCursor((const byte *)crosshairCursor, 40, 25, 20, 17);
+ break;
+ case kCursorCurrentItem:
+ CursorMan.replaceCursor((const byte *)mouseCursor, OBJWIDTH, OBJHEIGHT, 20, 17);
+ default:
+ break;
+ }
+}
+
+void DrasculaEngine::showCursor() {
+ CursorMan.showMouse(true);
+}
+
+void DrasculaEngine::hideCursor() {
+ CursorMan.showMouse(false);
+}
+
+bool DrasculaEngine::isCursorVisible() {
+ return CursorMan.isVisible();
+}
+
void DrasculaEngine::selectVerbFromBar() {
for (int n = 0; n < 7; n++) {
if (mouseX > _verbBarX[n] && mouseX < _verbBarX[n + 1] && n > 0) {
@@ -36,7 +61,7 @@ void DrasculaEngine::selectVerbFromBar() {
}
// no verb selected
- withoutVerb();
+ selectVerb(0);
}
void DrasculaEngine::selectVerb(int verb) {
@@ -50,10 +75,17 @@ void DrasculaEngine::selectVerb(int verb) {
addObject(pickedObject);
}
- copyBackground(OBJWIDTH * verb, c, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3);
+ for (int i = 0; i < OBJHEIGHT; i++)
+ memcpy(mouseCursor + i * OBJWIDTH, backSurface + OBJWIDTH * verb + (c + i) * 320, OBJWIDTH);
+ setCursor(kCursorCurrentItem);
- takeObject = 1;
- pickedObject = verb;
+ if (verb > 0) {
+ takeObject = 1;
+ pickedObject = verb;
+ } else {
+ takeObject = 0;
+ hasName = 0;
+ }
}
bool DrasculaEngine::confirmExit() {
@@ -61,7 +93,7 @@ bool DrasculaEngine::confirmExit() {
color_abc(kColorRed);
updateRoom();
- centerText(_textsys[_lang][1], 160, 87);
+ centerText(_textsys[1], 160, 87);
updateScreen();
delay(100);
@@ -114,7 +146,8 @@ void DrasculaEngine::clearMenu() {
}
void DrasculaEngine::enterName() {
- Common::KeyCode key;
+ Common::KeyCode key, prevkey = Common::KEYCODE_INVALID;
+ int counter = 0;
int v = 0, h = 0;
char select2[23];
strcpy(select2, " ");
@@ -123,17 +156,25 @@ void DrasculaEngine::enterName() {
copyBackground(115, 14, 115, 14, 176, 9, bgSurface, screenSurface);
print_abc(select2, 117, 15);
updateScreen();
+ _system->delayMillis(100);
+
key = getScan();
- delay(70);
- if (key != 0) {
+
+ // Artifically decrease repeat rate.
+ // Part of bug fix#2017432 DRASCULA: Typing is slow when you save a game
+ // Alternative is to roll our own event loop
+ if (key == prevkey)
+ if (++counter == 3) {
+ counter = 0;
+ prevkey = Common::KEYCODE_INVALID;
+ }
+
+ if (key != 0 && key != prevkey) {
+ prevkey = key;
if (key >= 0 && key <= 0xFF && isalpha(key))
select2[v] = tolower(key);
- else if ((key == Common::KEYCODE_LCTRL) || (key == Common::KEYCODE_RCTRL))
- select2[v] = '\164';
- else if (key >= Common::KEYCODE_0 && key <= Common::KEYCODE_9)
+ else if ((key >= Common::KEYCODE_0 && key <= Common::KEYCODE_9) || key == Common::KEYCODE_SPACE)
select2[v] = key;
- else if (key == Common::KEYCODE_SPACE)
- select2[v] = '\167';
else if (key == Common::KEYCODE_ESCAPE)
break;
else if (key == Common::KEYCODE_RETURN) {
@@ -185,25 +226,4 @@ void DrasculaEngine::showMap() {
}
}
-void DrasculaEngine::grr() {
- int length = 30;
-
- color_abc(kColorDarkGreen);
-
- playFile("s10.als");
-
- updateRoom();
- copyBackground(253, 110, 150, 65, 20, 30, drawSurface3, screenSurface);
-
- if (withVoices == 0)
- centerText("groaaarrrrgghhhh!", 153, 65);
-
- updateScreen();
-
- while (!isTalkFinished(&length));
-
- updateRoom();
- updateScreen();
-}
-
} // End of namespace Drascula
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index 01967d975d..c9c99aafa8 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -51,7 +51,9 @@ void DrasculaEngine::chooseObject(int object) {
if (takeObject == 1 && menuScreen == 0)
addObject(pickedObject);
}
- copyBackground(_x1d_menu[object], _y1d_menu[object], 0, 0, OBJWIDTH,OBJHEIGHT, backSurface, drawSurface3);
+ for (int i = 0; i < OBJHEIGHT; i++)
+ memcpy(mouseCursor + i * OBJWIDTH, backSurface + _x1d_menu[object] + (_y1d_menu[object] + i) * 320, OBJWIDTH);
+ setCursor(kCursorCurrentItem);
takeObject = 1;
pickedObject = object;
}
@@ -70,23 +72,10 @@ int DrasculaEngine::removeObject(int obj) {
return result;
}
-void DrasculaEngine::withoutVerb() {
- int c = (menuScreen == 1) ? 0 : 171;
-
- if (currentChapter == 5) {
- if (takeObject == 1 && pickedObject != 16)
- addObject(pickedObject);
- } else {
- if (takeObject == 1)
- addObject(pickedObject);
- }
- copyBackground(0, c, 0, 0, OBJWIDTH,OBJHEIGHT, backSurface, drawSurface3);
-
- takeObject = 0;
- hasName = 0;
-}
-
void DrasculaEngine::gotoObject(int pointX, int pointY) {
+ bool cursorVisible = isCursorVisible();
+ hideCursor();
+
if (currentChapter == 5 || currentChapter == 6) {
if (hare_se_ve == 0) {
curX = roomX;
@@ -113,6 +102,9 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
}
updateRoom();
updateScreen();
+
+ if (cursorVisible)
+ showCursor();
}
void DrasculaEngine::checkObjects() {
@@ -186,7 +178,7 @@ bool DrasculaEngine::pickupObject() {
}
updateEvents();
if (takeObject == 0)
- withoutVerb();
+ selectVerb(0);
return false;
}
@@ -256,7 +248,7 @@ void DrasculaEngine::updateVisible() {
if (roomNumber == 22 && flags[27] == 1)
visible[3] = 0;
if (roomNumber == 26 && flags[21] == 0)
- strcpy(objName[2], _textmisc[_lang][0]);
+ strcpy(objName[2], _textmisc[0]);
if (roomNumber == 26 && flags[18] == 1)
visible[2] = 0;
if (roomNumber == 26 && flags[12] == 1)
diff --git a/engines/drascula/palette.cpp b/engines/drascula/palette.cpp
index 6a93f21e55..ba174c9237 100644
--- a/engines/drascula/palette.cpp
+++ b/engines/drascula/palette.cpp
@@ -27,6 +27,17 @@
namespace Drascula {
+const char colorTable[][3] = {
+ { 0, 0, 0 }, { 0x10, 0x3E, 0x28 },
+ { 0, 0, 0 }, // unused
+ { 0x16, 0x3F, 0x16 }, { 0x09, 0x3F, 0x12 },
+ { 0x3F, 0x3F, 0x15 },
+ { 0, 0, 0 }, // unused
+ { 0x38, 0, 0 }, { 0x3F, 0x27, 0x0B },
+ { 0x2A, 0, 0x2A }, { 0x30, 0x30, 0x30 },
+ { 98, 91, 100 }
+};
+
void DrasculaEngine::setRGB(byte *pal, int colorCount) {
int x, cnt = 0;
@@ -70,17 +81,6 @@ void DrasculaEngine::setPalette(byte *PalBuf) {
void DrasculaEngine::color_abc(int cl) {
_color = cl;
- char colorTable[][3] = {
- { 0, 0, 0 }, { 0x10, 0x3E, 0x28 },
- { 0, 0, 0 }, // unused
- { 0x16, 0x3F, 0x16 }, { 0x09, 0x3F, 0x12 },
- { 0x3F, 0x3F, 0x15 },
- { 0, 0, 0 }, // unused
- { 0x38, 0, 0 }, { 0x3F, 0x27, 0x0B },
- { 0x2A, 0, 0x2A }, { 0x30, 0x30, 0x30 },
- { 98, 91, 100 }
- };
-
for (int i = 0; i <= 2; i++)
gamePalette[254][i] = colorTable[cl][i];
@@ -127,64 +127,25 @@ void DrasculaEngine::fadeFromBlack(int fadeSpeed) {
}
}
-void DrasculaEngine::assignDefaultPalette() {
+void DrasculaEngine::assignPalette(DacPalette256 pal) {
int color, component;
for (color = 235; color < 253; color++)
for (component = 0; component < 3; component++)
- defaultPalette[color][component] = gamePalette[color][component];
-}
-
-void DrasculaEngine::assignBrightPalette() {
- int color, component;
-
- for (color = 235; color < 253; color++) {
- for (component = 0; component < 3; component++)
- brightPalette[color][component] = gamePalette[color][component];
- }
-}
-
-void DrasculaEngine::assignDarkPalette() {
- int color, component;
-
- for (color = 235; color < 253; color++) {
- for (component = 0; component < 3; component++)
- darkPalette[color][component] = gamePalette[color][component];
- }
+ pal[color][component] = gamePalette[color][component];
}
-void DrasculaEngine::setDefaultPalette() {
+void DrasculaEngine::setDefaultPalette(DacPalette256 pal) {
int color, component;
for (color = 235; color < 253; color++) {
for (component = 0; component < 3; component++) {
- gamePalette[color][component] = defaultPalette[color][component];
+ gamePalette[color][component] = pal[color][component];
}
}
setPalette((byte *)&gamePalette);
}
-void DrasculaEngine::setBrightPalette() {
- int color, component;
-
- for (color = 235; color < 253; color++) {
- for (component = 0; component < 3; component++)
- gamePalette[color][component] = brightPalette[color][component];
- }
-
- setPalette((byte *)&gamePalette);
-}
-
-void DrasculaEngine::setDarkPalette() {
- int color, component;
-
- for (color = 235; color < 253; color++ )
- for (component = 0; component < 3; component++)
- gamePalette[color][component] = darkPalette[color][component];
-
- setPalette((byte *)&gamePalette);
-}
-
void DrasculaEngine::setPaletteBase(int darkness) {
signed char fade;
unsigned int color, component;
diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp
index 37dddf4b7e..027685f56a 100644
--- a/engines/drascula/rooms.cpp
+++ b/engines/drascula/rooms.cpp
@@ -29,6 +29,24 @@
namespace Drascula {
+struct doorInfo {
+ int chapter;
+ int doorNum;
+ int flag;
+};
+
+doorInfo doors[] = {
+ { 2, 138, 0 }, { 2, 136, 8 },
+ { 2, 156, 16 }, { 2, 163, 17 },
+ { 2, 177, 15 }, { 2, 175, 40 },
+ { 2, 173, 36 }, { 4, 103, 0 },
+ { 4, 104, 1 }, { 4, 105, 1 },
+ { 4, 106, 2 }, { 4, 107, 2 },
+ { 4, 110, 6 }, { 4, 114, 4 },
+ { 4, 115, 4 }, { 4, 117, 5 },
+ { 4, 120, 8 }, { 4, 122, 7 }
+};
+
typedef bool (DrasculaEngine::*RoomParser)(int args);
struct DrasculaRoomParser {
@@ -184,9 +202,9 @@ bool DrasculaEngine::room_3(int fl) {
if (pickedObject == kVerbTalk && fl == 129) {
talk(23);
pause(6);
- talk_sync(_text[_lang][50], "50.als", "11111111111144432554433");
+ talk_sync(_text[50], "50.als", "11111111111144432554433");
} else if (pickedObject == kVerbTalk && fl == 133) {
- talk_sync(_text[_lang][322], "322.als", "13333334125433333333");
+ talk_sync(_text[322], "322.als", "13333334125433333333");
updateRoom();
updateScreen();
pause(25);
@@ -248,11 +266,11 @@ bool DrasculaEngine::room_6(int fl) {
talk(41);
talk(42);
} else if (pickedObject == kVerbOpen && fl == 138)
- openDoor(0, 1);
+ toggleDoor(0, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 138)
- closeDoor(0, 1);
+ toggleDoor(0, 1, kCloseDoor);
else if (pickedObject == kVerbOpen && fl == 143 && flags[2] == 0) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface);
updateScreen();
@@ -263,7 +281,7 @@ bool DrasculaEngine::room_6(int fl) {
updateScreen();
finishSound();
} else if (pickedObject == kVerbClose && fl == 143 && flags[2] == 1) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
flags[2] = 0;
updateRefresh_pre();
copyRect(228, 102, curX + 5, curY - 1, 47, 73, drawSurface3, screenSurface);
@@ -274,7 +292,7 @@ bool DrasculaEngine::room_6(int fl) {
updateScreen();
finishSound();
} else if (pickedObject == kVerbOpen && fl == 139 && flags[1] == 0) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface);
updateScreen();
@@ -287,7 +305,7 @@ bool DrasculaEngine::room_6(int fl) {
updateScreen();
finishSound();
} else if (pickedObject == kVerbPick && fl == 140) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyRect(267, 1, curX - 14, curY - 2, 52, 73, drawSurface3, screenSurface);
updateScreen();
@@ -350,9 +368,9 @@ bool DrasculaEngine::room_9(int fl) {
bool DrasculaEngine::room_12(int fl) {
if (pickedObject == kVerbOpen && fl == 156)
- openDoor(16, 4);
+ toggleDoor(16, 4, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 156)
- closeDoor(16, 4);
+ toggleDoor(16, 4, kCloseDoor);
else
hasAnswer = 0;
@@ -365,11 +383,14 @@ bool DrasculaEngine::room_13(int fl) {
trackProtagonist = 3;
talk(412);
strcpy(objName[1], "yoda");
- } else if (pickedObject == kVerbTalk && fl == 51)
+ } else if (pickedObject == kVerbTalk && fl == 51) {
converse(7);
- else if (pickedObject == 19 && fl == 51)
- animation_1_3();
- else if (pickedObject == 9 && fl == 51) {
+ } else if (pickedObject == 19 && fl == 51) {
+ talk(413);
+ grr();
+ pause(50);
+ talk(414);
+ } else if (pickedObject == 9 && fl == 51) {
animation_2_3();
return true;
} else
@@ -404,10 +425,10 @@ bool DrasculaEngine::room_15(int fl) {
talk(336);
trackProtagonist = 3;
talk(337);
- talk_sync(_text[_lang][46], "46.als", "4442444244244");
+ talk_sync(_text[46], "46.als", "4442444244244");
trackProtagonist = 1;
} else if (pickedObject == 18 && fl == 188 && flags[26] == 0) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
copyRect(133, 135, curX + 6, curY, 39, 63, drawSurface3, screenSurface);
updateScreen();
playSound(8);
@@ -432,17 +453,17 @@ bool DrasculaEngine::room_15(int fl) {
bool DrasculaEngine::room_16(int fl) {
if (pickedObject == kVerbOpen && fl == 163)
- openDoor(17, 0);
+ toggleDoor(17, 0, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 163)
- closeDoor(17, 0);
+ toggleDoor(17, 0, kCloseDoor);
else if (pickedObject == kVerbTalk && fl == 183) {
talk(341);
pause(10);
- talk_sync(_text[_lang][50], "50.als", "11111111111144432554433");
+ talk_sync(_text[50], "50.als", "11111111111144432554433");
pause(3);
- talk_baul(83);
+ talk_trunk(83);
} else if (pickedObject == kVerbOpen && fl == 183) {
- openDoor(19, NO_DOOR);
+ toggleDoor(19, NO_DOOR, kOpenDoor);
if (flags[20] == 0) {
flags[20] = 1;
trackProtagonist = 3;
@@ -452,7 +473,7 @@ bool DrasculaEngine::room_16(int fl) {
pickObject(22);
}
} else if (pickedObject == kVerbClose && fl == 183)
- closeDoor(19, NO_DOOR);
+ toggleDoor(19, NO_DOOR, kCloseDoor);
else if (pickedObject == kVerbLook && fl == 187) {
talk(343);
trackProtagonist = 3;
@@ -470,16 +491,18 @@ bool DrasculaEngine::room_17(int fl) {
talk(35);
else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 0)
talk(6);
- else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 1)
- animation_18_2();
- else if (pickedObject == kVerbOpen && fl == 177 && flags[18] == 1)
+ else if (pickedObject == kVerbTalk && fl == 177 && flags[18] == 1) {
+ talk(378);
+ talk_vonBraun(4, kVonBraunDoor);
+ converse(3);
+ } else if (pickedObject == kVerbOpen && fl == 177 && flags[18] == 1)
talk(346);
else if (pickedObject == kVerbOpen && fl == 177 && flags[14] == 0 && flags[18] == 0)
- animation_22_2();
+ playTalkSequence(22); // sequence 22, chapter 2
else if (pickedObject == kVerbOpen && fl == 177 && flags[14] == 1)
- openDoor(15, 1);
+ toggleDoor(15, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 177 && flags[14] == 1)
- closeDoor(15, 1);
+ toggleDoor(15, 1, kCloseDoor);
else if (pickedObject == 11 && fl == 50 && flags[22] == 0) {
talk(347);
flags[29] = 1;
@@ -497,7 +520,7 @@ bool DrasculaEngine::room_18(int fl) {
else if (pickedObject == kVerbTalk && fl == 55 && flags[36] == 1)
talk(109);
else if (pickedObject == kVerbPick && fl == 182) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyRect(44, 1, curX, curY, 41, 70, drawSurface2, screenSurface);
updateRefresh();
@@ -519,7 +542,7 @@ bool DrasculaEngine::room_18(int fl) {
trackProtagonist = 3;
updateRoom();
updateScreen();
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyRect(1, 1, curX - 1, curY + 3, 42, 67, drawSurface2, screenSurface);
updateRefresh();
@@ -539,19 +562,20 @@ bool DrasculaEngine::room_21(int fl) {
if (pickedObject == kVerbOpen && fl == 101 && flags[28] == 0)
talk(419);
else if (pickedObject == kVerbOpen && fl == 101 && flags[28] == 1)
- openDoor(0, 1);
+ toggleDoor(0, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 101)
- closeDoor(0, 1);
+ toggleDoor(0, 1, kCloseDoor);
else if(pickedObject == kVerbPick && fl == 141) {
pickObject(19);
visible[2] = 0;
flags[10] = 1;
} else if(pickedObject == 7 && fl == 101) {
flags[28] = 1;
- openDoor(0, 1);
- withoutVerb();
+ toggleDoor(0, 1, kOpenDoor);
+ selectVerb(0);
} else if (pickedObject == 21 && fl == 179) {
- animation_9_4();
+ animate("st.bin", 14);
+ fadeToBlack(1);
return true;
} else
hasAnswer = 0;
@@ -570,7 +594,7 @@ bool DrasculaEngine::room_22(int fl) {
playSound(1);
hiccup(14);
finishSound();
- withoutVerb();
+ selectVerb(0);
removeObject(22);
updateVisible();
trackProtagonist = 3;
@@ -590,15 +614,15 @@ bool DrasculaEngine::room_22(int fl) {
bool DrasculaEngine::room_23(int fl) {
if (pickedObject == kVerbOpen && fl == 103) {
- openDoor(0, 0);
+ toggleDoor(0, 0, kOpenDoor);
updateVisible();
} else if(pickedObject == kVerbClose && fl == 103) {
- closeDoor(0, 0);
+ toggleDoor(0, 0, kCloseDoor);
updateVisible();
} else if(pickedObject == kVerbOpen && fl == 104)
- openDoor(1, 1);
+ toggleDoor(1, 1, kOpenDoor);
else if(pickedObject == kVerbClose && fl == 104)
- closeDoor(1, 1);
+ toggleDoor(1, 1, kCloseDoor);
else if(pickedObject == kVerbPick && fl == 142) {
pickObject(8);
visible[2] = 0;
@@ -615,13 +639,13 @@ bool DrasculaEngine::room_23(int fl) {
bool DrasculaEngine::room_24(int fl) {
if (pickedObject == kVerbOpen && fl == 105)
- openDoor(1, 0);
+ toggleDoor(1, 0, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 105)
- closeDoor(1, 0);
+ toggleDoor(1, 0, kCloseDoor);
else if (pickedObject == kVerbOpen && fl == 106)
- openDoor(2, 1);
+ toggleDoor(2, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 106)
- closeDoor(2, 1);
+ toggleDoor(2, 1, kCloseDoor);
else
hasAnswer = 0;
@@ -630,11 +654,11 @@ bool DrasculaEngine::room_24(int fl) {
bool DrasculaEngine::room_26(int fl) {
if (pickedObject == kVerbOpen && fl == 107 && flags[30] == 0)
- openDoor(2, 0);
+ toggleDoor(2, 0, kOpenDoor);
else if (pickedObject == kVerbOpen && fl == 107 && flags[30] == 1)
talk(421);
else if (pickedObject == kVerbClose && fl == 107)
- closeDoor(2, 0);
+ toggleDoor(2, 0, kCloseDoor);
else if (pickedObject == 10 && fl == 50 && flags[18] == 1 && flags[12] == 1)
animation_5_4();
else if (pickedObject == 8 && fl == 50 && flags[18] == 1 && flags[12] == 1)
@@ -648,7 +672,7 @@ bool DrasculaEngine::room_26(int fl) {
pickObject(10);
visible[1] = 0;
flags[12] = 1;
- closeDoor(2, 0);
+ toggleDoor(2, 0, kCloseDoor);
trackProtagonist = 2;
talk_igor(27, kIgorDoor);
flags[30] = 1;
@@ -671,17 +695,17 @@ bool DrasculaEngine::room_26(int fl) {
bool DrasculaEngine::room_27(int fl) {
if (pickedObject == kVerbOpen && fl == 110)
- openDoor(6, 1);
+ toggleDoor(6, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 110)
- closeDoor(6, 1);
+ toggleDoor(6, 1, kCloseDoor);
else if (pickedObject == kVerbOpen && fl == 116 && flags[23] == 0)
talk(419);
else if (pickedObject == kVerbOpen && fl == 116 && flags[23] == 1)
- openDoor(5, 3);
+ toggleDoor(5, 3, kOpenDoor);
else if (pickedObject == 17 && fl == 116) {
flags[23] = 1;
- openDoor(5,3);
- withoutVerb();
+ toggleDoor(5, 3, kOpenDoor);
+ selectVerb(0);
} else if (fl == 150)
talk(460);
else
@@ -692,9 +716,9 @@ bool DrasculaEngine::room_27(int fl) {
bool DrasculaEngine::room_29(int fl) {
if (pickedObject == kVerbOpen && fl == 114)
- openDoor(4, 1);
+ toggleDoor(4, 1, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 114)
- closeDoor(4, 1);
+ toggleDoor(4, 1, kCloseDoor);
else
hasAnswer = 0;
@@ -703,15 +727,15 @@ bool DrasculaEngine::room_29(int fl) {
bool DrasculaEngine::room_30(int fl) {
if (pickedObject == kVerbOpen && fl == 115)
- openDoor(4, 0);
+ toggleDoor(4, 0, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 115)
- closeDoor(4, 0);
+ toggleDoor(4, 0, kCloseDoor);
else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 0)
talk(422);
else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 1 && flags[22] == 1)
- openDoor(16, 1);
+ toggleDoor(16, 1, kOpenDoor);
else if (pickedObject == kVerbOpen && fl == 144 && flags[19] == 1 && flags[22] == 0) {
- openDoor(16, 1);
+ toggleDoor(16, 1, kOpenDoor);
talk(423);
flags[22] = 1;
pickObject(12);
@@ -720,7 +744,7 @@ bool DrasculaEngine::room_30(int fl) {
if (flags[18] == 1)
animation_6_4();
} else if (pickedObject == kVerbClose && fl == 144)
- closeDoor(16, 1);
+ toggleDoor(16, 1, kCloseDoor);
else if (pickedObject == 13 && fl == 144) {
talk(424);
flags[19] = 1;
@@ -736,9 +760,9 @@ bool DrasculaEngine::room_31(int fl) {
visible[1] = 0;
flags[13] = 1;
} else if (pickedObject == kVerbOpen && fl == 117)
- openDoor(5, 0);
+ toggleDoor(5, 0, kOpenDoor);
else if (pickedObject == kVerbClose && fl == 117)
- closeDoor(5, 0);
+ toggleDoor(5, 0, kCloseDoor);
else
hasAnswer = 0;
@@ -749,15 +773,15 @@ bool DrasculaEngine::room_34(int fl) {
if (pickedObject == kVerbMove && fl == 146)
animation_8_4();
else if (pickedObject == kVerbOpen && fl == 120 && flags[25] == 1)
- openDoor(8, 2);
+ toggleDoor(8, 2, kOpenDoor);
else if (pickedObject == kVerbOpen && fl == 120 && flags[25] == 0) {
- openDoor(8, 2);
+ toggleDoor(8, 2, kOpenDoor);
trackProtagonist = 3;
talk(425);
pickObject(14);
flags[25] = 1;
} else if (pickedObject == kVerbClose && fl == 120)
- closeDoor(8, 2);
+ toggleDoor(8, 2, kCloseDoor);
else
hasAnswer=0;
@@ -805,20 +829,27 @@ bool DrasculaEngine::room_53(int fl) {
if (pickedObject == kVerbPick && fl == 120) {
pickObject(16);
visible[3] = 0;
- } else if (pickedObject == kVerbMove && fl == 123)
+ } else if (pickedObject == kVerbMove && fl == 123) {
animation_11_5();
- else if (pickedObject == 12 && fl == 52)
- animation_10_5();
- else if (pickedObject == 15 && fl == 52)
- animation_9_5();
- else if (pickedObject == 16 && fl == 121) {
+ } else if (pickedObject == 12 && fl == 52) {
+ flags[3] = 1;
+ talk(401);
+ selectVerb(0);
+ removeObject(12);
+ } else if (pickedObject == 15 && fl == 52) {
+ flags[4] = 1;
+ talk(401);
+ selectVerb(0);
+ removeObject(15);
+ } else if (pickedObject == 16 && fl == 121) {
flags[2] = 1;
- withoutVerb();
+ selectVerb(0);
updateVisible();
+ pickedObject = kVerbMove;
} else if (pickedObject == 16) {
- talk(439);
- withoutVerb();
+ // Wall plug in chapter 5
visible[3] = 1;
+ hasAnswer = 0;
} else
hasAnswer = 0;
@@ -851,7 +882,7 @@ bool DrasculaEngine::room_54(int fl) {
} else if (pickedObject == 10 && fl == 119) {
pause(4);
talk(436);
- withoutVerb();
+ selectVerb(0);
removeObject(10);
} else
hasAnswer = 0;
@@ -886,10 +917,12 @@ bool DrasculaEngine::room_56(int fl) {
}
bool DrasculaEngine::room_58(int fl) {
- if (pickedObject == kVerbMove && fl == 103)
- animation_7_6();
- else
+ if (pickedObject == kVerbMove && fl == 103) {
+ flags[8] = 1;
+ updateVisible();
+ } else {
hasAnswer = 0;
+ }
return true;
}
@@ -933,19 +966,19 @@ bool DrasculaEngine::room_59(int fl) {
talk_htel(240);
color_abc(kColorBrown);
- talk_solo(_textvb[_lang][58], "VB58.als");
+ talk_solo(_textvb[58], "VB58.als");
talk_htel(241);
color_abc(kColorBrown);
- talk_solo(_textvb[_lang][59], "VB59.als");
+ talk_solo(_textvb[59], "VB59.als");
talk_htel(242);
color_abc(kColorBrown);
- talk_solo(_textvb[_lang][60], "VB60.als");
+ talk_solo(_textvb[60], "VB60.als");
talk_htel(196);
color_abc(kColorBrown);
- talk_solo(_textvb[_lang][61],"VB61.als");
+ talk_solo(_textvb[61],"VB61.als");
talk_htel(244);
color_abc(kColorBrown);
- talk_solo(_textvb[_lang][62], "VB62.als");
+ talk_solo(_textvb[62], "VB62.als");
clearRoom();
loadPic("aux59.alg", drawSurface3);
loadPic(96, frontSurface, COMPLETE_PAL);
@@ -953,7 +986,7 @@ bool DrasculaEngine::room_59(int fl) {
loadPic(59, bgSurface, HALF_PAL);
trackProtagonist = 3;
talk(245);
- withoutVerb();
+ selectVerb(0);
flags[11] = 1;
}
} else
@@ -963,17 +996,27 @@ bool DrasculaEngine::room_59(int fl) {
}
bool DrasculaEngine::room_60(int fl) {
- if (pickedObject == kVerbMove && fl == 112)
- animation_10_6();
- else if (pickedObject == kVerbTalk && fl == 52) {
+ if (pickedObject == kVerbMove && fl == 112) {
+ playSound(14);
+ copyBackground();
+ updateRefresh_pre();
+ copyBackground(164, 85, 155, 48, 113, 114, drawSurface3, screenSurface);
+ updateScreen();
+ finishSound();
+ talk_bartender(23, 1);
+ flags[7] = 1;
+ } else if (pickedObject == kVerbTalk && fl == 52) {
talk(266);
talk_bartender(1, 1);
converse(12);
- withoutVerb();
+ selectVerb(0);
pickedObject = 0;
- } else if (pickedObject == 21 && fl == 56)
- animation_18_6();
- else if (pickedObject == 9 && fl == 56 && flags[6] == 1) {
+ } else if (pickedObject == 21 && fl == 56) {
+ flags[6] = 1;
+ selectVerb(0);
+ removeObject(21);
+ animate("beb.bin", 10);
+ } else if (pickedObject == 9 && fl == 56 && flags[6] == 1) {
animation_9_6();
return true;
} else if (pickedObject == 9 && fl == 56 && flags[6] == 0) {
@@ -1089,11 +1132,9 @@ void DrasculaEngine::updateRefresh_pre() {
void DrasculaEngine::update_1_pre() {
if (curX > 98 && curX < 153) {
- changeColor = 1;
- setDarkPalette();
+ setDefaultPalette(darkPalette);
} else {
- changeColor = 0;
- setBrightPalette();
+ setDefaultPalette(brightPalette);
}
if (flags[8] == 0)
@@ -1101,8 +1142,8 @@ void DrasculaEngine::update_1_pre() {
}
void DrasculaEngine::update_2() {
- int batPos[6];
int difference;
+ int w, h;
int batX[] = {0, 38, 76, 114, 152, 190, 228, 266,
0, 38, 76, 114, 152, 190, 228, 266,
0, 38, 76, 114, 152, 190,
@@ -1122,24 +1163,19 @@ void DrasculaEngine::update_2() {
if (actorFrames[kFrameBat] == 41)
actorFrames[kFrameBat] = 0;
- batPos[0] = batX[actorFrames[kFrameBat]];
- batPos[1] = batY[actorFrames[kFrameBat]];
-
if (actorFrames[kFrameBat] < 22) {
- batPos[4] = 37;
- batPos[5] = 21;
+ w = 37;
+ h = 21;
} else if (actorFrames[kFrameBat] > 27) {
- batPos[4] = 57;
- batPos[5] = 36;
+ w = 57;
+ h = 36;
} else {
- batPos[4] = 47;
- batPos[5] = 22;
+ w = 47;
+ h = 22;
}
- batPos[2] = 239;
- batPos[3] = 19;
-
- copyRectClip(batPos, drawSurface3, screenSurface);
+ copyRect(batX[actorFrames[kFrameBat]], batY[actorFrames[kFrameBat]],
+ 239, 19, w, h, drawSurface3, screenSurface);
difference = getTime() - savedTime;
if (difference >= 6) {
actorFrames[kFrameBat]++;
@@ -1158,22 +1194,18 @@ void DrasculaEngine::update_3() {
void DrasculaEngine::update_4() {
if (curX > 190) {
- changeColor = 1;
- setDarkPalette();
+ setDefaultPalette(darkPalette);
} else {
- changeColor = 0;
- setBrightPalette();
+ setDefaultPalette(brightPalette);
}
}
void DrasculaEngine::update_6_pre() {
if ((curX > 149 && curY + curHeight > 160 && curX < 220 && curY + curHeight < 188) ||
(curX > 75 && curY + curHeight > 183 && curX < 145)) {
- changeColor = 0;
- setBrightPalette();
+ setDefaultPalette(brightPalette);
} else {
- changeColor = 1;
- setDarkPalette();
+ setDefaultPalette(darkPalette);
}
}
@@ -1463,6 +1495,7 @@ void DrasculaEngine::update_102() {
}
bool DrasculaEngine::checkAction(int fl) {
+ hideCursor();
characterMoved = 0;
updateRoom();
updateScreen();
@@ -1481,7 +1514,7 @@ bool DrasculaEngine::checkAction(int fl) {
|| (pickedObject == kVerbOpen && fl == 22 && flags[23] == 0)) {
talk(164);
flags[23] = 1;
- withoutVerb();
+ selectVerb(0);
addObject(kItemMoney);
addObject(kItemTwoCoins);
} else if (pickedObject == kVerbLook && fl == 22 && flags[23] == 1)
@@ -1492,7 +1525,7 @@ bool DrasculaEngine::checkAction(int fl) {
hasAnswer = 0;
} else if (currentChapter == 4) {
if ((pickedObject == 18 && fl == 19) || (pickedObject == 19 && fl == 18)) {
- withoutVerb();
+ selectVerb(0);
chooseObject(21);
removeObject(18);
removeObject(19);
@@ -1504,13 +1537,7 @@ bool DrasculaEngine::checkAction(int fl) {
talk(495);
} else
hasAnswer = 0;
- } else if (currentChapter == 5) {
- if (pickedObject == kVerbLook && fl == 9) {
- talk(482);
- talk(483);
- } else
- hasAnswer = 0;
- } else if (currentChapter == 6) {
+ } else if (currentChapter == 5 || currentChapter == 6) {
if (pickedObject == kVerbLook && fl == 9) {
talk(482);
talk(483);
@@ -1528,8 +1555,10 @@ bool DrasculaEngine::checkAction(int fl) {
hasAnswer = 0;
} else if (currentChapter == 3) {
if (roomNumber == 13) {
- if (room(13, fl))
+ if (room(13, fl)) {
+ showCursor();
return true;
+ }
} else
hasAnswer = 0;
} else if (currentChapter == 4) {
@@ -1540,14 +1569,18 @@ bool DrasculaEngine::checkAction(int fl) {
else if (pickedObject == 12 && fl == 50 && flags[18] == 0)
talk(487);
else if (roomNumber == 21) {
- if (room(21, fl))
+ if (room(21, fl)) {
+ showCursor();
return true;
+ }
} else
hasAnswer = 0;
} else if (currentChapter == 5) {
if (roomNumber == 56) {
- if (room(56, fl))
+ if (room(56, fl)) {
+ showCursor();
return true;
+ }
} else
hasAnswer = 0;
} else if (currentChapter == 6) {
@@ -1558,8 +1591,10 @@ bool DrasculaEngine::checkAction(int fl) {
else if (roomNumber == 102)
room(102, fl);
else if (roomNumber == 60) {
- if (room(60, fl))
+ if (room(60, fl)) {
+ showCursor();
return true;
+ }
}
else
hasAnswer = 0;
@@ -1575,6 +1610,7 @@ bool DrasculaEngine::checkAction(int fl) {
if (hasAnswer == 0 && (hasName == 1 || menuScreen == 1))
room(0, -1);
+ showCursor();
return false;
}
@@ -1600,6 +1636,7 @@ bool DrasculaEngine::room(int rN, int fl) {
void DrasculaEngine::enterRoom(int roomIndex) {
debug(2, "Entering room %d", roomIndex);
+ showCursor();
char fileName[20];
sprintf(fileName, "%d.ald", roomIndex);
@@ -1661,7 +1698,7 @@ void DrasculaEngine::enterRoom(int roomIndex) {
getIntFromLine(buffer, size, &_destX[l]);
getIntFromLine(buffer, size, &_destY[l]);
getIntFromLine(buffer, size, &trackCharacter_alkeva[l]);
- getIntFromLine(buffer, size, &alapuertakeva[l]);
+ getIntFromLine(buffer, size, &roomExits[l]);
updateDoor(l);
}
}
@@ -1716,16 +1753,15 @@ void DrasculaEngine::enterRoom(int roomIndex) {
copyBackground(0, 171, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3);
- setDefaultPalette();
+ setDefaultPalette(defaultPalette);
if (palLevel != 0)
setPaletteBase(palLevel);
- assignBrightPalette();
- setDefaultPalette();
+ assignPalette(brightPalette);
+ setDefaultPalette(defaultPalette);
setPaletteBase(palLevel + 2);
- assignDarkPalette();
+ assignPalette(darkPalette);
- setBrightPalette();
- changeColor = -1;
+ setDefaultPalette(brightPalette);
if (currentChapter == 2)
color_abc(kColorLightGreen);
@@ -1821,8 +1857,9 @@ void DrasculaEngine::enterRoom(int roomIndex) {
if (currentChapter == 5) {
if (roomNumber == 45)
hare_se_ve = 0;
- if (roomNumber == 49 && flags[7] == 0)
- animation_4_5();
+ if (roomNumber == 49 && flags[7] == 0) {
+ playTalkSequence(4); // sequence 4, chapter 5
+ }
}
updateRoom();
@@ -1830,7 +1867,7 @@ void DrasculaEngine::enterRoom(int roomIndex) {
void DrasculaEngine::clearRoom() {
memset(VGA, 0, 64000);
- _system->copyRectToScreen((const byte *)VGA, 320, 0, 0, 320, 200);
+ _system->clearScreen();
_system->updateScreen();
}
@@ -1839,49 +1876,50 @@ bool DrasculaEngine::exitRoom(int l) {
int roomNum = 0;
- if (currentChapter == 1) {
- if (objectNum[l] == 105 && flags[0] == 0)
- talk(442);
- else {
- updateDoor(l);
- if (isDoor[l] != 0) {
- gotoObject(roomObjX[l], roomObjY[l]);
- trackProtagonist = trackObj[l];
- updateRoom();
- updateScreen();
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
-
- if (objectNum[l] == 105) {
- animation_2_1();
- return true;
- }
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX = -1;
- enterRoom(roomNum);
- }
+ // Player can't exit the inn in chapter 1
+ if (currentChapter == 1 && objectNum[l] == 104) {
+ return false;
+ }
+
+ if (currentChapter == 1 && objectNum[l] == 105 && flags[0] == 0) {
+ talk(442);
+ return false;
+ }
+
+ updateDoor(l);
+ if (isDoor[l] != 0 &&
+ ((currentChapter != 3 && currentChapter != 5) || visible[l] == 1)) {
+
+ hideCursor();
+ gotoObject(roomObjX[l], roomObjY[l]);
+ if (currentChapter != 2) {
+ trackProtagonist = trackObj[l];
+ updateRoom();
+ updateScreen();
}
- } else if (currentChapter == 2) {
- updateDoor(l);
- if (isDoor[l] != 0) {
- gotoObject(roomObjX[l], roomObjY[l]);
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
+ characterMoved = 0;
+ trackProtagonist = trackCharacter_alkeva[l];
+ objExit = roomExits[l];
+ doBreak = 1;
+ previousMusic = roomMusic;
+
+ // Object specific actions
+ if (currentChapter == 1 && objectNum[l] == 105) {
+ animation_2_1();
+ return true;
+ } else if (currentChapter == 2) {
if (objectNum[l] == 136)
animation_2_2();
- if (objectNum[l] == 124)
- animation_3_2();
+ if (objectNum[l] == 124) {
+ gotoObject(163, 106);
+ gotoObject(287, 101);
+ trackProtagonist = 0;
+ }
if (objectNum[l] == 173) {
animation_35_2();
return true;
- } if (objectNum[l] == 146 && flags[39] == 1) {
+ }
+ if (objectNum[l] == 146 && flags[39] == 1) {
flags[5] = 1;
flags[11] = 1;
}
@@ -1890,93 +1928,27 @@ bool DrasculaEngine::exitRoom(int l) {
removeObject(kItemEarWithEarPlug);
addObject(kItemEarplugs);
}
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX =- 1;
- enterRoom(roomNum);
- }
- } else if (currentChapter == 3) {
- updateDoor(l);
- if (isDoor[l] != 0 && visible[l] == 1) {
- gotoObject(roomObjX[l], roomObjY[l]);
- trackProtagonist = trackObj[l];
- updateRoom();
- updateScreen();
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX =- 1;
- enterRoom(roomNum);
- }
- } else if (currentChapter == 4) {
- updateDoor(l);
- if (isDoor[l] != 0) {
- gotoObject(roomObjX[l], roomObjY[l]);
- trackProtagonist = trackObj[l];
- updateRoom();
- updateScreen();
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
-
- if (objectNum[l] == 108)
- gotoObject(171, 78);
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX = -1;
- enterRoom(roomNum);
+ } else if (currentChapter == 4 && objectNum[l] == 108) {
+ gotoObject(171, 78);
}
- } else if (currentChapter == 5) {
- updateDoor(l);
- if (isDoor[l] != 0 && visible[l] == 1) {
- gotoObject(roomObjX[l], roomObjY[l]);
- trackProtagonist = trackObj[l];
- updateRoom();
- updateScreen();
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
+
+ if (currentChapter == 5)
hare_se_ve = 1;
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX = -1;
- enterRoom(roomNum);
- }
- } else if (currentChapter == 6) {
- updateDoor(l);
- if (isDoor[l] != 0) {
- gotoObject(roomObjX[l], roomObjY[l]);
- trackProtagonist = trackObj[l];
- updateRoom();
- updateScreen();
- characterMoved = 0;
- trackProtagonist = trackCharacter_alkeva[l];
- objExit = alapuertakeva[l];
- doBreak = 1;
- previousMusic = roomMusic;
- clearRoom();
- sscanf(_targetSurface[l], "%d", &roomNum);
- curX = -1;
- enterRoom(roomNum);
- if (objExit == 105)
- animation_19_6();
- }
+ clearRoom();
+ sscanf(_targetSurface[l], "%d", &roomNum);
+ curX = -1;
+ enterRoom(roomNum);
+
+ if (currentChapter == 6 && objExit == 105)
+ animation_19_6();
}
return false;
}
void DrasculaEngine::updateRoom() {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
if (currentChapter == 3) {
if (flags[0] == 0)
@@ -1990,67 +1962,41 @@ void DrasculaEngine::updateRoom() {
}
void DrasculaEngine::updateDoor(int doorNum) {
- if (currentChapter == 1 || currentChapter == 3 || currentChapter == 5 || currentChapter == 6)
+ if (currentChapter != 2 && currentChapter != 4)
return;
- else if (currentChapter == 2) {
- if (objectNum[doorNum] == 138)
- isDoor[doorNum] = flags[0];
- else if (objectNum[doorNum] == 136)
- isDoor[doorNum] = flags[8];
- else if (objectNum[doorNum] == 156)
- isDoor[doorNum] = flags[16];
- else if (objectNum[doorNum] == 163)
- isDoor[doorNum] = flags[17];
- else if (objectNum[doorNum] == 177)
- isDoor[doorNum] = flags[15];
- else if (objectNum[doorNum] == 175)
- isDoor[doorNum] = flags[40];
- else if (objectNum[doorNum] == 173)
- isDoor[doorNum] = flags[36];
- } else if (currentChapter == 4) {
+
+ for (int i = 0; i < ARRAYSIZE(doors); i++) {
+ if (doors[i].chapter == currentChapter &&
+ objectNum[doorNum] == doors[i].doorNum) {
+ isDoor[doorNum] = flags[doors[i].flag];
+ return;
+ }
+ }
+
+ if (currentChapter == 4) {
if (objectNum[doorNum] == 101 && flags[0] == 0)
isDoor[doorNum] = 0;
else if (objectNum[doorNum] == 101 && flags[0] == 1 && flags[28] == 1)
isDoor[doorNum] = 1;
- else if (objectNum[doorNum] == 103)
- isDoor[doorNum] = flags[0];
- else if (objectNum[doorNum] == 104)
- isDoor[doorNum] = flags[1];
- else if (objectNum[doorNum] == 105)
- isDoor[doorNum] = flags[1];
- else if (objectNum[doorNum] == 106)
- isDoor[doorNum] = flags[2];
- else if (objectNum[doorNum] == 107)
- isDoor[doorNum] = flags[2];
- else if (objectNum[doorNum] == 110)
- isDoor[doorNum] = flags[6];
- else if (objectNum[doorNum] == 114)
- isDoor[doorNum] = flags[4];
- else if (objectNum[doorNum] == 115)
- isDoor[doorNum] = flags[4];
else if (objectNum[doorNum] == 116 && flags[5] == 0)
isDoor[doorNum] = 0;
else if (objectNum[doorNum] == 116 && flags[5] == 1 && flags[23] == 1)
isDoor[doorNum] = 1;
- else if (objectNum[doorNum] == 117)
- isDoor[doorNum] = flags[5];
- else if (objectNum[doorNum] == 120)
- isDoor[doorNum] = flags[8];
- else if (objectNum[doorNum] == 122)
- isDoor[doorNum] = flags[7];
}
}
-void DrasculaEngine::openDoor(int nflag, int doorNum) {
- if (flags[nflag] == 0) {
- if (currentChapter == 1 /*|| currentChapter == 4*/) {
- if (nflag != 7) {
- playSound(3);
- flags[nflag] = 1;
- }
- } else {
+void DrasculaEngine::toggleDoor(int nflag, int doorNum, int action) {
+ if ((flags[nflag] == 0 && action == kOpenDoor) ||
+ (flags[nflag] == 1 && action == kCloseDoor)) {
+ if (currentChapter == 1 && nflag == 7 && action == kOpenDoor)
+ return;
+
+ if (action == kOpenDoor) {
playSound(3);
flags[nflag] = 1;
+ } else {
+ playSound(4);
+ flags[nflag] = 0;
}
if (doorNum != NO_DOOR)
@@ -2058,20 +2004,7 @@ void DrasculaEngine::openDoor(int nflag, int doorNum) {
updateRoom();
updateScreen();
finishSound();
- withoutVerb();
- }
-}
-
-void DrasculaEngine::closeDoor(int nflag, int doorNum) {
- if (flags[nflag] == 1) {
- playSound(4);
- flags[nflag] = 0;
- if (doorNum != NO_DOOR)
- updateDoor(doorNum);
- updateRoom();
- updateScreen();
- finishSound();
- withoutVerb();
+ selectVerb(0);
}
}
diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp
index de82899462..503d2ab639 100644
--- a/engines/drascula/saveload.cpp
+++ b/engines/drascula/saveload.cpp
@@ -50,7 +50,7 @@ bool DrasculaEngine::saveLoadScreen() {
}
}
for (n = 0; n < NUM_SAVES; n++)
- sav->readLine(names[n], 23);
+ sav->readLine_OLD(names[n], 23);
delete sav;
loadPic("savescr.alg", bgSurface, HALF_PAL);
@@ -59,15 +59,17 @@ bool DrasculaEngine::saveLoadScreen() {
select[0] = 0;
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ setCursor(kCursorCrosshair);
+
for (;;) {
y = 27;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
for (n = 0; n < NUM_SAVES; n++) {
print_abc(names[n], 116, y);
y = y + 9;
}
print_abc(select, 117, 15);
- setCursorTable();
updateScreen();
y = 27;
@@ -140,8 +142,10 @@ bool DrasculaEngine::saveLoadScreen() {
}
if (mouseX > 125 && mouseY > 123 && mouseX < 199 && mouseY < 149 && selectionMade == 1) {
- if (!loadGame(file))
+ if (!loadGame(file)) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
return false;
+ }
break;
} else if (mouseX > 208 && mouseY > 123 && mouseX < 282 && mouseY < 149 && selectionMade == 1) {
saveGame(file);
@@ -168,10 +172,14 @@ bool DrasculaEngine::saveLoadScreen() {
delay(5);
}
+ selectVerb(0);
+
clearRoom();
loadPic(roomNumber, bgSurface, HALF_PAL);
selectionMade = 0;
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+
return true;
}
@@ -192,7 +200,7 @@ bool DrasculaEngine::loadGame(const char *gameName) {
if (savedChapter != currentChapter) {
strcpy(saveName, gameName);
currentChapter = savedChapter - 1;
- hay_que_load = 1;
+ loadedDifferentChapter = 1;
return false;
}
sav->read(currentData, 20);
@@ -210,10 +218,10 @@ bool DrasculaEngine::loadGame(const char *gameName) {
takeObject = sav->readSint32LE();
pickedObject = sav->readSint32LE();
- hay_que_load = 0;
+ loadedDifferentChapter = 0;
sscanf(currentData, "%d.ald", &roomNum);
enterRoom(roomNum);
- withoutVerb();
+ selectVerb(0);
return true;
}
@@ -247,9 +255,6 @@ void DrasculaEngine::saveGame(char gameName[]) {
warning("Can't write file '%s'. (Disk full?)", gameName);
delete out;
-
- playSound(99);
- finishSound();
}
} // End of namespace Drascula
diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp
index 840d6c7cb5..6a3d83cae6 100644
--- a/engines/drascula/sound.cpp
+++ b/engines/drascula/sound.cpp
@@ -23,6 +23,10 @@
*
*/
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
#include "drascula/drascula.h"
namespace Drascula {
@@ -37,25 +41,31 @@ void DrasculaEngine::updateVolume(Audio::Mixer::SoundType soundType, int prevVol
}
void DrasculaEngine::volumeControls() {
- int masterVolume, voiceVolume, musicVolume;
+ if (_lang == kSpanish)
+ loadPic(95, tableSurface);
copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface);
updateScreen(73, 63, 73, 63, 177, 97, screenSurface);
- masterVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16) * 4);
- voiceVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 16) * 4);
- musicVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 16) * 4);
+ setCursor(kCursorCrosshair);
+ showCursor();
for (;;) {
+ int masterVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16), 0, 15);
+ int voiceVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 16), 0, 15);
+ int musicVolume = CLIP((_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 16), 0, 15);
+
+ int masterVolumeY = 72 + 61 - masterVolume * 4;
+ int voiceVolumeY = 72 + 61 - voiceVolume * 4;
+ int musicVolumeY = 72 + 61 - musicVolume * 4;
+
updateRoom();
copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface);
- copyBackground(183, 56, 82, masterVolume, 39, 2 + ((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16) * 4), tableSurface, screenSurface);
- copyBackground(183, 56, 138, voiceVolume, 39, 2 + ((_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 16) * 4), tableSurface, screenSurface);
- copyBackground(183, 56, 194, musicVolume, 39, 2 + ((_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 16) * 4), tableSurface, screenSurface);
-
- setCursorTable();
+ copyBackground(183, 56, 82, masterVolumeY, 39, 2 + masterVolume * 4, tableSurface, screenSurface);
+ copyBackground(183, 56, 138, voiceVolumeY, 39, 2 + voiceVolume * 4, tableSurface, screenSurface);
+ copyBackground(183, 56, 194, musicVolumeY, 39, 2 + musicVolume * 4, tableSurface, screenSurface);
updateScreen();
@@ -68,23 +78,25 @@ void DrasculaEngine::volumeControls() {
if (leftMouseButton == 1) {
delay(100);
if (mouseX > 80 && mouseX < 121) {
- updateVolume(Audio::Mixer::kPlainSoundType, mouseY);
- masterVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) / 16) * 4);
+ updateVolume(Audio::Mixer::kPlainSoundType, masterVolumeY);
}
if (mouseX > 136 && mouseX < 178) {
- updateVolume(Audio::Mixer::kSFXSoundType, mouseY);
- voiceVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 16) * 4);
+ updateVolume(Audio::Mixer::kSFXSoundType, voiceVolumeY);
}
if (mouseX > 192 && mouseX < 233) {
- updateVolume(Audio::Mixer::kMusicSoundType, mouseY);
- musicVolume = 72 + 61 - ((_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 16) * 4);
+ updateVolume(Audio::Mixer::kMusicSoundType, musicVolumeY);
}
}
}
+ if (_lang == kSpanish)
+ loadPic(974, tableSurface);
+
+ selectVerb(0);
+
updateEvents();
}
@@ -111,6 +123,10 @@ void DrasculaEngine::stopMusic() {
AudioCD.stop();
}
+void DrasculaEngine::updateMusic() {
+ AudioCD.updateCD();
+}
+
int DrasculaEngine::musicStatus() {
return AudioCD.isPlaying();
}
@@ -142,7 +158,18 @@ void DrasculaEngine::playFile(const char *fname) {
if (_arj.open(fname)) {
int soundSize = _arj.size();
byte *soundData = (byte *)malloc(soundSize);
- _arj.seek(32);
+
+ if (!(!strcmp(fname, "3.als") && soundSize == 145166 && _lang != kSpanish)) {
+ _arj.seek(32);
+ } else {
+ // WORKAROUND: File 3.als with English speech files has a big silence at
+ // its beginning and end. We seek past the silence at the beginning,
+ // and ignore the silence at the end
+ // Fixes bug #2111815 - "DRASCULA: Voice delayed"
+ _arj.seek(73959, SEEK_SET);
+ soundSize = 117158 - 73959;
+ }
+
_arj.read(soundData, soundSize);
_arj.close();
diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp
index a89c5ff734..7bf55b7c40 100644
--- a/engines/drascula/talk.cpp
+++ b/engines/drascula/talk.cpp
@@ -36,9 +36,8 @@ void DrasculaEngine::talkInit(const char *filename) {
playFile(filename);
}
-bool DrasculaEngine::isTalkFinished(int* length) {
- byte key = getScan();
- if (key != 0)
+bool DrasculaEngine::isTalkFinished() {
+ if (getScan() != 0)
stopSound();
if (soundIsActive())
return false;
@@ -55,13 +54,12 @@ bool DrasculaEngine::isTalkFinished(int* length) {
void DrasculaEngine::talk_igor(int index, int talkerType) {
char filename[20];
sprintf(filename, "I%i.als", index);
- const char *said = _texti[_lang][index];
+ const char *said = _texti[index];
int x_talk0[8] = { 56, 82, 108, 134, 160, 186, 212, 238 };
int x_talk1[8] = { 56, 86, 116, 146, 176, 206, 236, 266 };
int x_talk3[4] = { 80, 102, 124, 146 };
int x_talk4[4] = { 119, 158, 197, 236 };
int face = 0;
- int length = strlen(said);
color_abc(kColorWhite);
@@ -70,11 +68,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {
do {
if (talkerType == kIgorDch || talkerType == kIgorFront) {
face = _rnd->getRandomNumber(7);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
} else if (talkerType == kIgorSeated || talkerType == kIgorWig) {
face = _rnd->getRandomNumber(3);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
}
@@ -119,7 +117,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {
updateScreen();
pause(3);
}
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
if ((talkerType == kIgorFront && currentChapter == 6) ||
talkerType == kIgorDoor || talkerType == kIgorSeated || talkerType == kIgorWig) {
@@ -127,7 +125,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {
}
if (talkerType == kIgorDch || (talkerType == kIgorFront && currentChapter == 1)) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
placeIgor();
placeDrascula();
}
@@ -136,12 +134,11 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {
// Talker type 0: talk_dr_izq, 1: talk_dr_dch
void DrasculaEngine::talk_drascula(int index, int talkerType) {
- const char *said = _textd[_lang][index];
+ const char *said = _textd[index];
char filename[20];
sprintf(filename, "d%i.als", index);
int x_talk[8] = { 1, 40, 79, 118, 157, 196, 235, 274 };
int face;
- int length = strlen(said);
int offset = (talkerType == 0) ? 0 : 7;
int offset2 = (talkerType == 0) ? 90 : 58;
@@ -152,7 +149,7 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {
do {
face = _rnd->getRandomNumber(7);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
@@ -176,10 +173,10 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
if (talkerType == 0)
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
if (talkerType == 1 && currentChapter == 6)
updateRoom();
@@ -193,8 +190,41 @@ void DrasculaEngine::talk_drascula(int index, int talkerType) {
updateScreen();
}
+void DrasculaEngine::talk_drascula_big(int index) {
+ char filename[20];
+ sprintf(filename, "d%i.als", index);
+ const char *said = _textd[index];
+ int x_talk[4] = {47, 93, 139, 185};
+ int face;
+ int l = 0;
+
+ color_abc(kColorRed);
+
+ talkInit(filename);
+
+ do {
+ face = _rnd->getRandomNumber(3);
+ copyBackground();
+ copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface);
+ copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface);
+ l++;
+ if (l == 7)
+ l = 0;
+
+ if (withVoices == 0)
+ centerText(said, 191, 69);
+
+ updateScreen();
+
+ pause(3);
+
+ byte key = getScan();
+ if (key == Common::KEYCODE_ESCAPE)
+ term_int = 1;
+ } while (!isTalkFinished());
+}
+
void DrasculaEngine::talk_solo(const char *said, const char *filename) {
- int length = strlen(said);
if (currentChapter == 1)
color_abc(color_solo);
@@ -204,7 +234,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) {
talkInit(filename);
if (currentChapter == 6)
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
do {
if (withVoices == 0) {
@@ -216,10 +246,10 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) {
centerText(said, 173, 92);
}
updateScreen();
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
if (currentChapter == 6) {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
}
}
@@ -231,15 +261,14 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) {
// Line 82 is a special case
if (index != 82)
- said = _textt[_lang][index];
+ said = _textt[index];
else {
sprintf(filename, "d%i.als", index);
- said = _textd[_lang][index];
+ said = _textd[index];
}
int x_talk[9] = { 1, 23, 45, 67, 89, 111, 133, 155, 177 };
int face;
- int length = strlen(said);
color_abc(kColorMaroon);
@@ -260,7 +289,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) {
face = _rnd->getRandomNumber(5);
}
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
@@ -277,7 +306,7 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) {
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
updateRoom();
updateScreen();
@@ -286,10 +315,9 @@ void DrasculaEngine::talk_bartender(int index, int talkerType) {
void DrasculaEngine::talk_bj(int index) {
char filename[20];
sprintf(filename, "BJ%i.als", index);
- const char *said = _textbj[_lang][index];
+ const char *said = _textbj[index];
int x_talk[5] = { 64, 92, 120, 148, 176 };
int face;
- int length = strlen(said);
color_abc(kColorWhite);
@@ -299,7 +327,7 @@ void DrasculaEngine::talk_bj(int index) {
if (currentChapter != 5) {
face = _rnd->getRandomNumber(4);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
@@ -325,7 +353,7 @@ void DrasculaEngine::talk_bj(int index) {
updateScreen();
}
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
updateRoom();
updateScreen();
@@ -334,7 +362,7 @@ void DrasculaEngine::talk_bj(int index) {
void DrasculaEngine::talk(int index) {
char name[20];
sprintf(name, "%i.als", index);
- talk(_text[_lang][index], name);
+ talk(_text[index], name);
}
void DrasculaEngine::talk(const char *said, const char *filename) {
@@ -344,7 +372,6 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
int y_mask_talk = 170;
int face;
- int length = strlen(said);
if (currentChapter == 6) {
if (flags[0] == 0 && roomNumber == 102) {
@@ -375,7 +402,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
do {
face = _rnd->getRandomNumber(5);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
if (currentChapter == 2)
@@ -442,7 +469,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
updateRoom();
updateScreen();
@@ -456,7 +483,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
void DrasculaEngine::talk_pianist(int index) {
char filename[20];
sprintf(filename, "P%i.als", index);
- const char* said = _textp[_lang][index];
+ const char* said = _textp[index];
int x_talk[4] = { 97, 145, 193, 241 };
int coords[7] = { 139, 228, 112, 47, 60, 221, 128 };
@@ -467,7 +494,7 @@ void DrasculaEngine::talk_pianist(int index) {
void DrasculaEngine::talk_drunk(int index) {
char filename[20];
sprintf(filename, "B%i.als", index);
- const char *said = _textb[_lang][index];
+ const char *said = _textb[index];
int x_talk[8] = { 1, 21, 41, 61, 81, 101, 121, 141 };
int coords[7] = { 29, 177, 50, 19, 19, 181, 54 };
@@ -498,13 +525,15 @@ void DrasculaEngine::talk_drunk(int index) {
}
}
-void DrasculaEngine::talk_vonBraun(int index) {
+// talker types:
+// 0: kVonBraunNormal
+// 1: KVonBraunDoor
+void DrasculaEngine::talk_vonBraun(int index, int talkerType) {
char filename[20];
sprintf(filename, "VB%i.als", index);
- const char *said = _textvb[_lang][index];
+ const char *said = _textvb[index];
int x_talk[6] = {1, 27, 53, 79, 105, 131};
int face;
- int length = strlen(said);
color_abc(kColorBrown);
@@ -513,50 +542,33 @@ void DrasculaEngine::talk_vonBraun(int index) {
copyBackground(vonBraunX + 5, 64, OBJWIDTH + 1, 0, 25, 27, bgSurface, drawSurface3);
do {
- if (trackVonBraun == 1) {
- face = _rnd->getRandomNumber(5);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
-
- moveCharacters();
- moveVonBraun();
+ if (talkerType == kVonBraunNormal) {
+ if (trackVonBraun == 1) {
+ face = _rnd->getRandomNumber(5);
+ copyBackground();
- copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface);
- copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface);
- updateRefresh();
- }
+ moveCharacters();
+ moveVonBraun();
- if (withVoices == 0)
- centerText(said, vonBraunX, 66);
-
- updateScreen();
-
- pause(3);
- } while (!isTalkFinished(&length));
-
- updateRoom();
- updateScreen();
- if (musicStatus() == 0 && flags[11] == 0 && roomMusic != 0)
- playMusic(roomMusic);
-}
-
-void DrasculaEngine::talk_vonBraunpuerta(int index) {
- char filename[20];
- sprintf(filename, "VB%i.als", index);
- const char *said = _textvb[_lang][index];
- int length = strlen(said);
-
- color_abc(kColorBrown);
+ copyBackground(OBJWIDTH + 1, 0, vonBraunX + 5, 64, 25, 27, drawSurface3, screenSurface);
+ copyRect(x_talk[face], 34, vonBraunX + 5, 64, 25, 27, frontSurface, screenSurface);
+ updateRefresh();
+ }
- talkInit(filename);
+ if (withVoices == 0)
+ centerText(said, vonBraunX, 66);
- do {
- updateRoom();
+ updateScreen();
+ pause(3);
+ } else {
+ updateRoom();
- if (withVoices == 0)
- centerText(said, 150, 80);
+ if (withVoices == 0)
+ centerText(said, 150, 80);
- updateScreen();
- } while (!isTalkFinished(&length));
+ updateScreen();
+ }
+ } while (!isTalkFinished());
updateRoom();
updateScreen();
@@ -570,60 +582,56 @@ void DrasculaEngine::talk_blind(int index) {
// voice files start from 58, not 1
char filename[20];
sprintf(filename, "d%i.als", index + TEXTD_START - 1);
- const char *said = _textd[_lang][index + TEXTD_START - 1];
- const char *syncChar = _textd1[_lang][index - 1];
+ const char *said = _textd[index + TEXTD_START - 1];
+ const char *syncChar = _textd1[index - 1];
- byte *faceBuffer;
int p = 0;
- int pos_blind[6] = { 0, 2, 73, 1, 126, 149 };
- int length = strlen(said);
+ int bX = 0;
+ int h = 149;
color_abc(kColorBrown);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
talkInit(filename);
do {
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
- pos_blind[5] = 149;
+ copyBackground();
+ h = 149;
char c = toupper(syncChar[p]);
if (c == '0' || c == '2' || c == '4' || c == '6')
- pos_blind[0] = 1;
+ bX = 1;
else
- pos_blind[0] = 132;
+ bX = 132;
if (c == '0' || c == '1')
- faceBuffer = drawSurface3;
+ copyRect(bX, 2, 73, 1, 126, h, drawSurface3, screenSurface);
else if (c == '2' || c == '3')
- faceBuffer = extraSurface;
+ copyRect(bX, 2, 73, 1, 126, h, extraSurface, screenSurface);
else if (c == '4' || c == '5')
- faceBuffer = backSurface;
+ copyRect(bX, 2, 73, 1, 126, h, backSurface, screenSurface);
else {
- faceBuffer = frontSurface;
- pos_blind[5] = 146;
+ h = 146;
+ copyRect(bX, 2, 73, 1, 126, h, frontSurface, screenSurface);
}
- copyRectClip( pos_blind, faceBuffer, screenSurface);
-
if (withVoices == 0)
- centerText(said, 310, 71);
+ centerText(said, 260, 71);
updateScreen();
pause(2);
p++;
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
}
void DrasculaEngine::talk_hacker(int index) {
char filename[20];
sprintf(filename, "d%i.als", index);
- const char *said = _textd[_lang][index];
- int length = strlen(said);
+ const char *said = _textd[index];
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
color_abc(kColorYellow);
@@ -634,13 +642,13 @@ void DrasculaEngine::talk_hacker(int index) {
if (withVoices == 0)
centerText(said, 156, 170);
updateScreen();
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
}
void DrasculaEngine::talk_werewolf(int index) {
char filename[20];
sprintf(filename, "L%i.als", index);
- const char *said = _textl[_lang][index];
+ const char *said = _textl[index];
int x_talk[9] = {52, 79, 106, 133, 160, 187, 214, 241, 268};
int coords[7] = { 136, 198, 81, 26, 24, 203, 78 };
@@ -651,7 +659,7 @@ void DrasculaEngine::talk_werewolf(int index) {
void DrasculaEngine::talk_mus(int index) {
char filename[20];
sprintf(filename, "E%i.als", index);
- const char *said = _texte[_lang][index];
+ const char *said = _texte[index];
int x_talk[8] = { 16, 35, 54, 73, 92, 111, 130, 149};
int coords[7] = { 156, 190, 64, 18, 24, 197, 64 };
@@ -663,7 +671,6 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker
int x_talk[8] = {112, 138, 164, 190, 216, 242, 268, 294};
int x_talk2[5] = {122, 148, 174, 200, 226};
int face;
- int length = strlen(said);
flags[1] = 1;
@@ -683,7 +690,7 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker
else
face = _rnd->getRandomNumber(4);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
if (talkerType == 0)
@@ -703,10 +710,10 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
flags[1] = 0;
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
updateScreen();
}
@@ -714,10 +721,9 @@ void DrasculaEngine::talk_pen(const char *said, const char *filename, int talker
void DrasculaEngine::talk_bj_bed(int index) {
char filename[20];
sprintf(filename, "BJ%i.als", index);
- const char *said = _textbj[_lang][index];
+ const char *said = _textbj[index];
int x_talk[5] = {51, 101, 151, 201, 251};
int face;
- int length = strlen(said);
color_abc(kColorWhite);
@@ -726,7 +732,7 @@ void DrasculaEngine::talk_bj_bed(int index) {
do {
face = _rnd->getRandomNumber(4);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
@@ -741,7 +747,7 @@ void DrasculaEngine::talk_bj_bed(int index) {
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
updateRoom();
updateScreen();
@@ -750,11 +756,9 @@ void DrasculaEngine::talk_bj_bed(int index) {
void DrasculaEngine::talk_htel(int index) {
char filename[20];
sprintf(filename, "%i.als", index);
- const char *said = _text[_lang][index];
- char *faceBuffer;
+ const char *said = _text[index];
int x_talk[3] = {1, 94, 187};
int face, curScreen;
- int length = strlen(said);
color_abc(kColorYellow);
@@ -764,25 +768,23 @@ void DrasculaEngine::talk_htel(int index) {
face = _rnd->getRandomNumber(2);
curScreen = _rnd->getRandomNumber(2);
+ copyBackground();
+
if (face == 0 && curScreen == 0)
- faceBuffer = (char *)drawSurface3;
+ copyBackground(x_talk[face], 1, 45, 24, 92, 108, drawSurface3, screenSurface);
else if (curScreen == 1)
- faceBuffer = (char *)frontSurface;
+ copyBackground(x_talk[face], 1, 45, 24, 92, 108, frontSurface, screenSurface);
else
- faceBuffer = (char *)backSurface;
-
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
-
- copyBackground(x_talk[face], 1, 45, 24, 92, 108, (byte *)faceBuffer, screenSurface);
-
+ copyBackground(x_talk[face], 1, 45, 24, 92, 108, backSurface, screenSurface);
+
if (withVoices == 0)
centerText(said, 90, 50);
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateScreen();
}
@@ -790,7 +792,6 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha
int talkOffset = 1;
int y_mask_talk = 170;
int p, face = 0;
- int length = strlen(said);
char buf[2];
color_abc(kColorYellow);
@@ -808,7 +809,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha
strncpy(buf, &syncChar[p], 1);
face = atoi(buf);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
if (currentChapter == 2)
@@ -863,7 +864,7 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha
p++;
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
if (currentChapter == 1 && musicStatus() == 0 && flags[11] == 0)
playMusic(roomMusic);
@@ -871,12 +872,11 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha
playMusic(roomMusic);
}
-void DrasculaEngine::talk_baul(int index) {
+void DrasculaEngine::talk_trunk(int index) {
char filename[20];
sprintf(filename, "d%i.als", index);
- const char *said = _text[_lang][index];
+ const char *said = _text[index];
int face = 0, cara_antes;
- int length = strlen(said);
cara_antes = flags[19];
@@ -896,57 +896,21 @@ void DrasculaEngine::talk_baul(int index) {
updateScreen();
pause(4);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
flags[19] = cara_antes;
updateRoom();
updateScreen();
}
-void DrasculaEngine::talk_dr_grande(int index) {
- char filename[20];
- sprintf(filename, "D%i.als", index);
- const char *said = _textd[_lang][index];
- int x_talk[4] = {47, 93, 139, 185};
- int face;
- int l = 0;
- int length = strlen(said);
-
- color_abc(kColorRed);
-
- talkInit(filename);
-
- do {
- face = _rnd->getRandomNumber(3);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
- copyBackground(interf_x[l] + 24, interf_y[l], 0, 45, 39, 31, drawSurface2, screenSurface);
- copyBackground(x_talk[face], 1, 171, 68, 45, 48, drawSurface2, screenSurface);
- l++;
- if (l == 7)
- l = 0;
-
- if (withVoices == 0)
- centerText(said, 191, 69);
-
- updateScreen();
-
- pause(3);
-
- byte key = getScan();
- if (key == Common::KEYCODE_ESCAPE)
- term_int = 1;
- } while (!isTalkFinished(&length));
-}
-
void DrasculaEngine::talk_generic(const char* said, const char* filename, int* faces, int faceCount, int* coords, byte* surface) {
int face;
- int length = strlen(said);
talkInit(filename);
do {
face = _rnd->getRandomNumber(faceCount - 1);
- copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface);
+ copyBackground();
updateRefresh_pre();
copyBackground(faces[face], coords[0], coords[1], coords[2],
coords[3], coords[4], surface, screenSurface);
@@ -959,7 +923,27 @@ void DrasculaEngine::talk_generic(const char* said, const char* filename, int* f
updateScreen();
pause(3);
- } while (!isTalkFinished(&length));
+ } while (!isTalkFinished());
+
+ updateRoom();
+ updateScreen();
+}
+
+
+void DrasculaEngine::grr() {
+ color_abc(kColorDarkGreen);
+
+ playFile("s10.als");
+
+ updateRoom();
+ copyBackground(253, 110, 150, 65, 20, 30, drawSurface3, screenSurface);
+
+ if (withVoices == 0)
+ centerText("groaaarrrrgghhhh!", 153, 65);
+
+ updateScreen();
+
+ while (!isTalkFinished());
updateRoom();
updateScreen();
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 757a77f82b..1d3368b10d 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -36,7 +36,10 @@
#include "common/savefile.h"
#include "common/system.h"
#include "gui/message.h"
+#include "gui/newgui.h"
#include "sound/mixer.h"
+#include "engines/dialogs.h"
+#include "engines/metaengine.h"
#ifdef _WIN32_WCE
extern bool isSmartphone(void);
@@ -53,8 +56,9 @@ Engine::Engine(OSystem *syst)
_eventMan(_system->getEventManager()),
_saveFileMan(_system->getSavefileManager()),
_targetName(ConfMan.getActiveDomainName()),
- _gameDataPath(ConfMan.get("path")),
- _pauseLevel(0) {
+ _gameDataDir(ConfMan.get("path")),
+ _pauseLevel(0),
+ _mainMenuDialog(NULL) {
g_engine = this;
_autosavePeriod = ConfMan.getInt("autosave_period");
@@ -72,7 +76,8 @@ Engine::Engine(OSystem *syst)
Engine::~Engine() {
_mixer->stopAll();
-
+
+ delete _mainMenuDialog;
g_engine = NULL;
}
@@ -145,12 +150,12 @@ void Engine::checkCD() {
char buffer[MAXPATHLEN];
int i;
- if (strlen(_gameDataPath.c_str()) == 0) {
+ if (_gameDataDir.getPath().empty()) {
// That's it! I give up!
if (getcwd(buffer, MAXPATHLEN) == NULL)
return;
} else
- strncpy(buffer, _gameDataPath.c_str(), MAXPATHLEN);
+ strncpy(buffer, _gameDataDir.getPath().c_str(), MAXPATHLEN);
for (i = 0; i < MAXPATHLEN - 1; i++) {
if (buffer[i] == '\\')
@@ -210,3 +215,50 @@ void Engine::pauseEngineIntern(bool pause) {
// By default, just (un)pause all digital sounds
_mixer->pauseAll(pause);
}
+
+void Engine::mainMenuDialog() {
+ if (!_mainMenuDialog)
+ _mainMenuDialog = new MainMenuDialog(this);
+ runDialog(*_mainMenuDialog);
+ syncSoundSettings();
+}
+
+int Engine::runDialog(Dialog &dialog) {
+
+ pauseEngine(true);
+
+ int result = dialog.runModal();
+
+ pauseEngine(false);
+
+ return result;
+}
+
+void Engine::syncSoundSettings() {
+
+ // Sync the engine with the config manager
+ int soundVolumeMusic = ConfMan.getInt("music_volume");
+ int soundVolumeSFX = ConfMan.getInt("sfx_volume");
+ int soundVolumeSpeech = ConfMan.getInt("speech_volume");
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
+}
+
+void Engine::quitGame() {
+ Common::Event event;
+
+ event.type = Common::EVENT_QUIT;
+ _eventMan->pushEvent(event);
+}
+
+bool Engine::hasFeature(int f) {
+ const EnginePlugin *plugin = 0;
+ Common::String gameid = ConfMan.get("gameid");
+ gameid.toLowercase();
+ EngineMan.findGame(gameid, &plugin);
+
+ return ( (*plugin)->hasFeature((MetaEngine::MetaEngineFeature)f) );
+}
+
diff --git a/engines/engine.h b/engines/engine.h
index 73d529cc62..81e4e6187c 100644
--- a/engines/engine.h
+++ b/engines/engine.h
@@ -25,10 +25,13 @@
#ifndef ENGINES_ENGINE_H
#define ENGINES_ENGINE_H
+#include "common/events.h"
+#include "common/fs.h"
#include "common/scummsys.h"
#include "common/str.h"
class OSystem;
+
namespace Audio {
class Mixer;
}
@@ -39,8 +42,11 @@ namespace Common {
}
namespace GUI {
class Debugger;
+ class Dialog;
}
+using GUI::Dialog;
+
class Engine {
public:
OSystem *_system;
@@ -50,9 +56,13 @@ public:
protected:
Common::EventManager *_eventMan;
Common::SaveFileManager *_saveFileMan;
+
+ Dialog *_mainMenuDialog;
+ virtual int runDialog(Dialog &dialog);
const Common::String _targetName; // target name for saves
- const Common::String _gameDataPath;
+
+ const Common::FilesystemNode _gameDataDir;
private:
/**
@@ -82,7 +92,7 @@ public:
* Start the main engine loop.
* The return value is not yet used, but could indicate whether the user
* wants to return to the launch or to fully quit ScummVM.
- * @return a result code
+ * @return 0 for success, else an error code.
*/
virtual int go() = 0;
@@ -109,10 +119,32 @@ public:
void pauseEngine(bool pause);
/**
+ * Quit the engine, sends a Quit event to the Event Manager
+ */
+ void quitGame();
+
+ /**
* Return whether the engine is currently paused or not.
*/
bool isPaused() const { return _pauseLevel != 0; }
+ /**
+ * Return whether or not the ENGINE should quit
+ */
+ bool quit() const { return (_eventMan->shouldQuit() || _eventMan->shouldRTL()); }
+
+ /** Run the Global Main Menu Dialog
+ */
+ virtual void mainMenuDialog();
+
+ /** Sync the engine's sound settings with the config manager
+ */
+ virtual void syncSoundSettings();
+
+ /** Determine whether the engine supports the specified MetaEngine feature
+ */
+ virtual bool hasFeature(int f);
+
public:
/** Setup the backend's graphics mode. */
diff --git a/base/game.cpp b/engines/game.cpp
index e65c891dc7..b3cb140e0a 100644
--- a/base/game.cpp
+++ b/engines/game.cpp
@@ -23,7 +23,7 @@
*
*/
-#include "base/game.h"
+#include "engines/game.h"
#include "base/plugins.h"
#include "graphics/surface.h"
@@ -69,9 +69,48 @@ void GameDescriptor::updateDesc(const char *extra) {
}
void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
- if (_thumbnail && _thumbnail != t) {
- _thumbnail->free();
- delete _thumbnail;
+ if (_thumbnail.get() == t)
+ return;
+
+ _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter());
+}
+
+bool SaveStateDescriptor::getBool(const Common::String &key) const {
+ if (contains(key)) {
+ Common::String value = getVal(key);
+ if (value.equalsIgnoreCase("true") ||
+ value.equalsIgnoreCase("yes") ||
+ value.equals("1"))
+ return true;
+ if (value.equalsIgnoreCase("false") ||
+ value.equalsIgnoreCase("no") ||
+ value.equals("0"))
+ return false;
+ error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'",
+ save_slot().c_str(), description().c_str(), value.c_str(), key.c_str());
}
- _thumbnail = t;
+ return false;
+}
+
+void SaveStateDescriptor::setDeletableFlag(bool state) {
+ setVal("is_deletable", state ? "true" : "false");
+}
+
+void SaveStateDescriptor::setSaveDate(int year, int month, int day) {
+ char buffer[32];
+ snprintf(buffer, 32, "%.2d.%.2d.%.4d", day, month, year);
+ setVal("save_date", buffer);
+}
+
+void SaveStateDescriptor::setSaveTime(int hour, int min) {
+ char buffer[32];
+ snprintf(buffer, 32, "%.2d:%.2d", hour, min);
+ setVal("save_time", buffer);
}
+
+void SaveStateDescriptor::setPlayTime(int hours, int minutes) {
+ char buffer[32];
+ snprintf(buffer, 32, "%.2d:%.2d", hours, minutes);
+ setVal("play_time", buffer);
+}
+
diff --git a/base/game.h b/engines/game.h
index d81f2afb8a..a1eed7acd9 100644
--- a/base/game.h
+++ b/engines/game.h
@@ -23,12 +23,13 @@
*
*/
-#ifndef BASE_GAME_H
-#define BASE_GAME_H
+#ifndef ENGINES_GAME_H
+#define ENGINES_GAME_H
#include "common/str.h"
#include "common/array.h"
#include "common/hash-str.h"
+#include "common/ptr.h"
namespace Graphics {
struct Surface;
@@ -119,15 +120,16 @@ public:
*/
class SaveStateDescriptor : public Common::StringMap {
protected:
- Graphics::Surface *_thumbnail; // can be NULL
+ Common::SharedPtr<Graphics::Surface> _thumbnail; // can be 0
+
public:
- SaveStateDescriptor() : _thumbnail(0) {
+ SaveStateDescriptor() : _thumbnail() {
setVal("save_slot", "-1"); // FIXME: default to 0 (first slot) or to -1 (invalid slot) ?
setVal("description", "");
setVal("filename", "");
}
- SaveStateDescriptor(int s, const Common::String &d, const Common::String &f) : _thumbnail(0) {
+ SaveStateDescriptor(int s, const Common::String &d, const Common::String &f) : _thumbnail() {
char buf[16];
sprintf(buf, "%d", s);
setVal("save_slot", buf);
@@ -135,16 +137,12 @@ public:
setVal("filename", f);
}
- SaveStateDescriptor(const Common::String &s, const Common::String &d, const Common::String &f) : _thumbnail(0) {
+ SaveStateDescriptor(const Common::String &s, const Common::String &d, const Common::String &f) : _thumbnail() {
setVal("save_slot", s);
setVal("description", d);
setVal("filename", f);
}
- ~SaveStateDescriptor() {
- setThumbnail(0);
- }
-
/** The saveslot id, as it would be passed to the "-x" command line switch. */
Common::String &save_slot() { return getVal("save_slot"); }
@@ -163,21 +161,47 @@ public:
/** The filename of the savestate, for use with the SaveFileManager API (read-only variant). */
const Common::String &filename() const { return getVal("filename"); }
+ /** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */
+
+ /**
+ * Returns the value of a given key as boolean.
+ * It accepts 'true', 'yes' and '1' for true and
+ * 'false', 'no' and '0' for false.
+ * (FIXME:) On unknown value it errors out ScummVM.
+ * On unknown key it returns false as default.
+ */
+ bool getBool(const Common::String &key) const;
+
+ /**
+ * Sets the 'is_deletable' key, which indicates, if the
+ * given savestate is safe for deletion.
+ */
+ void setDeletableFlag(bool state);
+
/**
* Return a thumbnail graphics surface representing the savestate visually
* This is usually a scaled down version of the game graphics. The size
* should be either 160x100 or 160x120 pixels, depending on the aspect
* ratio of the game. If another ratio is required, contact the core team.
- *
- * TODO: it is probably a bad idea to read this for *all* games at once,
- * at least on low-end devices. So this info should probably normally only
- * be included optionally. I.e. only upon a query for a specific savegame...
- * To this end, add a getFullSaveStateInfo(target, slot) to the plugin API.
*/
- const Graphics::Surface *getThumbnail() const { return _thumbnail; }
-
+ const Graphics::Surface *getThumbnail() const { return _thumbnail.get(); }
void setThumbnail(Graphics::Surface *t);
+
+ /**
+ * Sets the 'save_date' key properly, based on the given values
+ */
+ void setSaveDate(int year, int month, int day);
+
+ /**
+ * Sets the 'save_time' key properly, based on the given values
+ */
+ void setSaveTime(int hour, int min);
+
+ /**
+ * Sets the 'play_time' key properly, based on the given values
+ */
+ void setPlayTime(int hours, int minutes);
};
/** List of savestates. */
diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp
index bcf566d134..d154a01de9 100644
--- a/engines/gob/dataio.cpp
+++ b/engines/gob/dataio.cpp
@@ -62,38 +62,40 @@ DataStream::~DataStream() {
}
}
-uint32 DataStream::pos() const {
+int32 DataStream::pos() const {
if (_stream)
return _stream->pos();
- uint32 resPos = _io->getChunkPos(_handle);
- if (resPos != 0xFFFFFFFF)
+ int32 resPos = _io->getChunkPos(_handle);
+ if (resPos != -1)
return resPos;
return _io->file_getHandle(_handle)->pos();
}
-uint32 DataStream::size() const {
+int32 DataStream::size() const {
if (_stream)
return _stream->size();
return _size;
}
-void DataStream::seek(int32 offset, int whence) {
+bool DataStream::seek(int32 offset, int whence) {
if (_stream)
- _stream->seek(offset, whence);
+ return _stream->seek(offset, whence);
else if ((_handle < 50) || (_handle >= 128))
- _io->file_getHandle(_handle)->seek(offset, whence);
- else
- _io->seekChunk(_handle, offset, whence);
+ return _io->file_getHandle(_handle)->seek(offset, whence);
+ else {
+ _io->seekChunk(_handle, offset, whence);
+ return true;
+ }
}
bool DataStream::eos() const {
if (_stream)
return _stream->eos();
- return pos() >= size();
+ return pos() >= size(); // FIXME (eos definition change)
}
uint32 DataStream::read(void *dataPtr, uint32 dataSize) {
diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h
index 4b4c79d1eb..c67dc89df8 100644
--- a/engines/gob/dataio.h
+++ b/engines/gob/dataio.h
@@ -45,10 +45,10 @@ public:
DataStream(byte *buf, uint32 dSize, bool dispose = true);
virtual ~DataStream();
- virtual uint32 pos() const;
- virtual uint32 size() const;
+ virtual int32 pos() const;
+ virtual int32 size() const;
- virtual void seek(int32 offset, int whence = SEEK_SET);
+ virtual bool seek(int32 offset, int whence = SEEK_SET);
virtual bool eos() const;
diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp
index 63a0f8f45b..2b0c015677 100644
--- a/engines/gob/detection.cpp
+++ b/engines/gob/detection.cpp
@@ -57,6 +57,7 @@ static const PlainGameDescriptor gobGames[] = {
{"inca2", "Inca II: Wiracocha"},
{"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"},
{"dynasty", "The Last Dynasty"},
+ {"urban", "Urban Runner"},
{0, 0}
};
@@ -277,6 +278,19 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesNone,
"intro"
},
+ {
+ {
+ "gob1",
+ "Interactive Demo",
+ AD_ENTRY1s("intro.stk", "a796096280d5efd48cf8e7dfbe426eb5", 193595),
+ UNK_LANG,
+ kPlatformPC,
+ Common::ADGF_DEMO
+ },
+ kGameTypeGob1,
+ kFeaturesNone,
+ "intro"
+ },
{ // Supplied by raina in the forums
{
"gob1",
@@ -900,6 +914,19 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesNone,
"intro"
},
+ { // Supplied by kizkoool in bugreport #2089734
+ {
+ "bargon",
+ "",
+ AD_ENTRY1s("intro.stk", "00f6b4e2ee26e5c40b488e2df5adcf03", 3975580),
+ FR_FRA,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeBargon,
+ kFeaturesNone,
+ "intro"
+ },
{ // Supplied by glorfindel in bugreport #1722142
{
"bargon",
@@ -1043,6 +1070,84 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesCD,
"intro"
},
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ EN_USA,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ FR_FRA,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ IT_ITA,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ DE_DEU,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ ES_ESP,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
+ { // Supplied by SiRoCs in bug report #2093672
+ {
+ "lostintime",
+ "",
+ AD_ENTRY1s("intro.stk", "795be7011ec31bf5bb8ce4efdb9ee5d3", 4838904),
+ EN_GRB,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeLostInTime,
+ kFeaturesCD,
+ "intro"
+ },
{
{
"lostintime",
@@ -1190,6 +1295,19 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesAdlib,
"intro"
},
+ { // Supplied by SiRoCs in bug report #2098621
+ {
+ "gob3",
+ "",
+ AD_ENTRY1s("intro.stk", "d3b72938fbbc8159198088811f9e6d19", 160382),
+ ES_ESP,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeGob3,
+ kFeaturesAdlib,
+ "intro"
+ },
{
{
"gob3",
@@ -1762,6 +1880,19 @@ static const GOBGameDescription gameDescriptions[] = {
kFeatures640,
"intro"
},
+ { // Supplied by goodoldgeorg in bug report #2098838
+ {
+ "woodruff",
+ "",
+ AD_ENTRY1s("intro.stk", "08a96bf061af1fa4f75c6a7cc56b60a4", 20734979),
+ PL_POL,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeWoodruff,
+ kFeatures640,
+ "intro"
+ },
{
{
"dynasty",
@@ -1771,7 +1902,7 @@ static const GOBGameDescription gameDescriptions[] = {
kPlatformPC,
Common::ADGF_NO_FLAGS
},
- kGameTypeWoodruff,
+ kGameTypeDynasty,
kFeatures640,
"intro"
},
@@ -1784,7 +1915,20 @@ static const GOBGameDescription gameDescriptions[] = {
kPlatformPC,
Common::ADGF_NO_FLAGS
},
- kGameTypeWoodruff,
+ kGameTypeDynasty,
+ kFeatures640,
+ "intro"
+ },
+ {
+ {
+ "urban",
+ "",
+ AD_ENTRY1s("intro.stk", "3ab2c542bd9216ae5d02cc6f45701ae1", 1252436),
+ EN_USA,
+ kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeUrban,
kFeatures640,
"intro"
},
@@ -1972,9 +2116,15 @@ public:
return "Goblins Games (C) Coktel Vision";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
};
+bool GobMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL);
+}
+
bool GobMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Gob::GOBGameDescription *gd = (const Gob::GOBGameDescription *)desc;
if (gd) {
diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp
index 8a7de9bdaa..7136646018 100644
--- a/engines/gob/draw.cpp
+++ b/engines/gob/draw.cpp
@@ -323,7 +323,38 @@ void Draw::adjustCoords(char adjust, int16 *coord1, int16 *coord2) {
}
}
-void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2,
+int Draw::stringLength(const char *str, int16 fontIndex) {
+ static const int8 dword_8F74C[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if ((fontIndex < 0) || (fontIndex > 7) || !_fonts[fontIndex])
+ return 0;
+
+ int len = 0;
+
+ if (_vm->_global->_language == 10) {
+
+ for (int i = 0; str[i] != 0; i++) {
+ if (((unsigned char) str[i+1]) < 128) {
+ len += dword_8F74C[4];
+ i++;
+ } else
+ len += _fonts[fontIndex]->itemWidth;
+ }
+
+ } else {
+
+ if (_fonts[fontIndex]->extraData)
+ while (*str != 0)
+ len += *(_fonts[fontIndex]->extraData + (*str++ - _fonts[fontIndex]->startItem));
+ else
+ len = (strlen(str) * _fonts[fontIndex]->itemWidth);
+
+ }
+
+ return len;
+}
+
+void Draw::drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
int16 transp, SurfaceDesc *dest, Video::FontDesc *font) {
while (*str != '\0') {
@@ -337,7 +368,7 @@ void Draw::drawString(char *str, int16 x, int16 y, int16 color1, int16 color2,
}
void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right,
- int16 bottom, char *str, int16 fontIndex, int16 color) {
+ int16 bottom, const char *str, int16 fontIndex, int16 color) {
adjustCoords(1, &left, &top);
adjustCoords(1, &right, &bottom);
diff --git a/engines/gob/draw.h b/engines/gob/draw.h
index 9ba589aa53..897208a42d 100644
--- a/engines/gob/draw.h
+++ b/engines/gob/draw.h
@@ -69,7 +69,7 @@ public:
int16 _destSurface;
char _letterToPrint;
- char *_textToPrint;
+ const char *_textToPrint;
int16 _backDeltaX;
int16 _backDeltaY;
@@ -146,10 +146,11 @@ public:
void adjustCoords(char adjust, uint16 *coord1, uint16 *coord2) {
adjustCoords(adjust, (int16 *) coord1, (int16 *) coord2);
}
- void drawString(char *str, int16 x, int16 y, int16 color1, int16 color2,
+ int stringLength(const char *str, int16 fontIndex);
+ void drawString(const char *str, int16 x, int16 y, int16 color1, int16 color2,
int16 transp, SurfaceDesc *dest, Video::FontDesc *font);
void printTextCentered(int16 id, int16 left, int16 top, int16 right,
- int16 bottom, char *str, int16 fontIndex, int16 color);
+ int16 bottom, const char *str, int16 fontIndex, int16 color);
int32 getSpriteRectSize(int16 index);
void forceBlit(bool backwards = false);
diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp
index 66deea8ec4..0ecbc81358 100644
--- a/engines/gob/game_v1.cpp
+++ b/engines/gob/game_v1.cpp
@@ -63,7 +63,7 @@ void Game_v1::playTot(int16 skipPlay) {
strcpy(savedTotName, _curTotFile);
if (skipPlay <= 0) {
- while (!_vm->_quitRequested) {
+ while (!_vm->quit()) {
for (int i = 0; i < 4; i++) {
_vm->_draw->_fontToSprite[i].sprite = -1;
_vm->_draw->_fontToSprite[i].base = -1;
@@ -997,7 +997,7 @@ void Game_v1::collisionsBlock(void) {
WRITE_VAR(16, 0);
_activeCollResId = 0;
}
- while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->_quitRequested);
+ while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->quit());
if (((uint16) _activeCollResId & ~0x8000) == collResId) {
collStackPos = 0;
diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp
index adf75176ab..7d9419b592 100644
--- a/engines/gob/game_v2.cpp
+++ b/engines/gob/game_v2.cpp
@@ -70,7 +70,7 @@ void Game_v2::playTot(int16 skipPlay) {
strcpy(savedTotName, _curTotFile);
if (skipPlay <= 0) {
- while (!_vm->_quitRequested) {
+ while (!_vm->quit()) {
if (_vm->_inter->_variables)
_vm->_draw->animateCursor(4);
@@ -438,7 +438,7 @@ int16 Game_v2::checkCollisions(byte handleMouse, int16 deltaTime, int16 *pResId,
timeKey = _vm->_util->getTimeKey();
while (1) {
- if (_vm->_inter->_terminate || _vm->_quitRequested) {
+ if (_vm->_inter->_terminate || _vm->quit()) {
if (handleMouse)
_vm->_draw->blitCursor();
return 0;
@@ -1043,7 +1043,7 @@ void Game_v2::collisionsBlock(void) {
WRITE_VAR(16, 0);
_activeCollResId = 0;
}
- while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->_quitRequested);
+ while ((_activeCollResId == 0) && !_vm->_inter->_terminate && !_vm->quit());
if ((_activeCollResId & 0xFFF) == collResId) {
collStackPos = 0;
@@ -1465,7 +1465,7 @@ int16 Game_v2::inputArea(int16 xPos, int16 yPos, int16 width, int16 height,
key = checkCollisions(handleMouse, -300, collResId, collIndex);
if ((key != 0) || (*collResId != 0) ||
- _vm->_inter->_terminate || _vm->_quitRequested)
+ _vm->_inter->_terminate || _vm->quit())
break;
if (*pTotTime > 0) {
@@ -1479,7 +1479,7 @@ int16 Game_v2::inputArea(int16 xPos, int16 yPos, int16 width, int16 height,
}
if ((key == 0) || (*collResId != 0) ||
- _vm->_inter->_terminate || _vm->_quitRequested)
+ _vm->_inter->_terminate || _vm->quit())
return 0;
switch (key) {
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 34443251d8..7e364e891d 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -24,7 +24,6 @@
*/
#include "common/endian.h"
-#include "common/events.h"
#include "base/plugins.h"
#include "common/config-manager.h"
@@ -62,7 +61,9 @@ const Common::Language GobEngine::_gobToScummVMLang[] = {
Common::EN_USA,
Common::NL_NLD,
Common::KO_KOR,
- Common::HB_ISR
+ Common::HB_ISR,
+ Common::PT_BRA,
+ Common::JA_JPN
};
GobEngine::GobEngine(OSystem *syst) : Engine(syst) {
@@ -82,7 +83,6 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) {
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
_copyProtection = ConfMan.getBool("copy_protection");
- _quitRequested = false;
Common::addSpecialDebugLevel(kDebugFuncOp, "FuncOpcodes", "Script FuncOpcodes debug level");
Common::addSpecialDebugLevel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level");
@@ -115,12 +115,8 @@ int GobEngine::go() {
return 0;
}
-void GobEngine::shutdown() {
- _quitRequested = true;
-}
-
const char *GobEngine::getLangDesc(int16 language) const {
- if ((language < 0) || (language > 8))
+ if ((language < 0) || (language > 10))
language = 2;
return Common::getLanguageDescription(_gobToScummVMLang[language]);
}
@@ -244,6 +240,12 @@ int GobEngine::init() {
case Common::HB_ISR:
_global->_language = 8;
break;
+ case Common::PT_BRA:
+ _global->_language = 9;
+ break;
+ case Common::JA_JPN:
+ _global->_language = 10;
+ break;
default:
// Default to English
_global->_language = 2;
@@ -387,6 +389,34 @@ bool GobEngine::initGameParts() {
_saveLoad = new SaveLoad_v4(this, _targetName.c_str());
break;
+ case kGameTypeDynasty:
+ _init = new Init_v3(this);
+ _video = new Video_v2(this);
+ _inter = new Inter_v5(this);
+ _parse = new Parse_v2(this);
+ _mult = new Mult_v2(this);
+ _draw = new Draw_v2(this);
+ _game = new Game_v2(this);
+ _map = new Map_v4(this);
+ _goblin = new Goblin_v4(this);
+ _scenery = new Scenery_v2(this);
+ _saveLoad = new SaveLoad_v4(this, _targetName.c_str());
+ break;
+
+ case kGameTypeUrban:
+ _init = new Init_v3(this);
+ _video = new Video_v6(this);
+ _inter = new Inter_v6(this);
+ _parse = new Parse_v2(this);
+ _mult = new Mult_v2(this);
+ _draw = new Draw_v2(this);
+ _game = new Game_v2(this);
+ _map = new Map_v4(this);
+ _goblin = new Goblin_v4(this);
+ _scenery = new Scenery_v2(this);
+ _saveLoad = new SaveLoad_v4(this, _targetName.c_str());
+ break;
+
default:
deinitGameParts();
return false;
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index 041658baea..39950e3261 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -93,7 +93,9 @@ enum GameType {
kGameTypeBargon,
kGameTypeWeen,
kGameTypeLostInTime,
- kGameTypeInca2
+ kGameTypeInca2,
+ kGameTypeDynasty,
+ kGameTypeUrban
};
enum Features {
@@ -209,7 +211,6 @@ public:
char *_startTot0;
bool _copyProtection;
bool _noMusic;
- bool _quitRequested;
Global *_global;
Util *_util;
@@ -229,8 +230,6 @@ public:
SaveLoad *_saveLoad;
VideoPlayer *_vidPlayer;
- void shutdown();
-
const char *getLangDesc(int16 language) const;
void validateLanguage();
void validateVideoMode(int16 videoMode);
diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp
index 5add0b9cea..55758cdfdc 100644
--- a/engines/gob/goblin.cpp
+++ b/engines/gob/goblin.cpp
@@ -652,7 +652,7 @@ void Goblin::adjustDest(int16 posX, int16 posY) {
if ((_vm->_map->getPass(_pressedMapX, _pressedMapY) == 0) &&
((_gobAction == 0) ||
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0))) {
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0))) {
resDelta = -1;
resDeltaDir = 0;
@@ -727,17 +727,17 @@ void Goblin::adjustDest(int16 posX, int16 posY) {
void Goblin::adjustTarget(void) {
if ((_gobAction == 4) &&
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) {
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0)) {
if ((_pressedMapY > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) {
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) {
_pressedMapY--;
} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {
_pressedMapX++;
} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
(_pressedMapY > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {
_pressedMapY--;
_pressedMapX++;
}
@@ -747,7 +747,7 @@ void Goblin::adjustTarget(void) {
}
void Goblin::targetDummyItem(Gob_Object *gobDesc) {
- if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 &&
+ if (_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0 &&
_vm->_map->getPass(_pressedMapX, _pressedMapY) == 1) {
if (gobDesc->curLookDir == 0) {
_vm->_map->_itemPoses[0].x = _pressedMapX;
@@ -771,7 +771,7 @@ void Goblin::targetItem(void) {
Gob_Object *itemDesc;
if ((_gobAction == 3) || (_gobAction == 4)) {
- items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX];
+ items = _vm->_map->getItem(_pressedMapX, _pressedMapY);
if ((_gobAction == 4) && ((items & 0xFF00) != 0) &&
(_objects[_itemToObject[(items & 0xFF00) >> 8]]->pickable == 1)) {
_destItemId = (items & 0xFF00) >> 8;
@@ -802,40 +802,40 @@ void Goblin::targetItem(void) {
_gobDestX = _vm->_map->_itemPoses[_destItemId].x;
} else if ((items & 0xFF00) != 0) {
if (_vm->_map->_itemPoses[_destItemId].orient == 4) {
- if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] & 0xFF00) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) {
+ if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) & 0xFF00) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {
_pressedMapX--;
_vm->_map->_destX = _pressedMapX;
_gobDestX = _pressedMapX;
}
} else if (_vm->_map->_itemPoses[_destItemId].orient == 0) {
- if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] & 0xFF00) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) {
+ if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) & 0xFF00) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {
_pressedMapX++;
_vm->_map->_destX = _pressedMapX;
_gobDestX = _pressedMapX;
}
}
- if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] & 0xFF00) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xFF00)) {
+ if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) & 0xFF00) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY) & 0xFF00)) {
_pressedMapY++;
_vm->_map->_destY = _pressedMapY;
_gobDestY = _pressedMapY;
}
} else {
if (_vm->_map->_itemPoses[_destItemId].orient == 4) {
- if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1]) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) {
+ if ((_vm->_map->getItem(_pressedMapX - 1, _pressedMapY)) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY))) {
_pressedMapX--;
_vm->_map->_destX = _pressedMapX;
_gobDestX = _pressedMapX;
}
} else if (_vm->_map->_itemPoses[_destItemId].orient == 0) {
- if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1]) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) {
+ if ((_vm->_map->getItem(_pressedMapX + 1, _pressedMapY)) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY))) {
_pressedMapX++;
_vm->_map->_destX = _pressedMapX;
_gobDestX = _pressedMapX;
@@ -843,8 +843,8 @@ void Goblin::targetItem(void) {
}
if (_pressedMapY < (_vm->_map->_mapHeight-1)) {
- if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX]) ==
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) {
+ if ((_vm->_map->getItem(_pressedMapX, _pressedMapY + 1)) ==
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY))) {
_pressedMapY++;
_vm->_map->_destY = _pressedMapY;
_gobDestY = _pressedMapY;
@@ -931,37 +931,37 @@ void Goblin::moveFindItem(int16 posX, int16 posY) {
_pressedMapX = CLIP(posX / 12, 0, _vm->_map->_mapWidth - 1);
_pressedMapY = CLIP(posY / 6, 0, _vm->_map->_mapHeight - 1);
- if ((_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) && (i < 20)) {
+ if ((_vm->_map->getItem(_pressedMapX, _pressedMapY) == 0) && (i < 20)) {
if ((_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
- (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] != 0)) {
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY + 1) != 0)) {
_pressedMapY++;
} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
(_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
- (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX + 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY + 1) != 0)) {
_pressedMapX++;
_pressedMapY++;
} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY) != 0)) {
_pressedMapX++;
} else if ((_pressedMapX < (_vm->_map->_mapWidth - 1)) &&
(_pressedMapY > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX + 1, _pressedMapY - 1) != 0)) {
_pressedMapX++;
_pressedMapY--;
} else if ((_pressedMapY > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0)) {
+ (_vm->_map->getItem(_pressedMapX, _pressedMapY - 1) != 0)) {
_pressedMapY--;
} else if ((_pressedMapY > 0) && (_pressedMapX > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX - 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY - 1) != 0)) {
_pressedMapY--;
_pressedMapX--;
} else if ((_pressedMapX > 0) &&
- (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY) != 0)) {
_pressedMapX--;
} else if ((_pressedMapX > 0) &&
(_pressedMapY < (_vm->_map->_mapHeight - 1)) &&
- (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX - 1] != 0)) {
+ (_vm->_map->getItem(_pressedMapX - 1, _pressedMapY + 1) != 0)) {
_pressedMapX--;
_pressedMapY++;
}
@@ -1384,11 +1384,11 @@ void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) {
for (int y = 0; y < _vm->_map->_mapHeight; y++) {
for (int x = 0; x < _vm->_map->_mapWidth; x++) {
if (_itemByteFlag == 1) {
- if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPocket)
- _vm->_map->_itemsMap[y][x] &= 0xFF;
+ if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPocket)
+ _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF);
} else {
- if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPocket)
- _vm->_map->_itemsMap[y][x] &= 0xFF00;
+ if ((_vm->_map->getItem(x, y) & 0xFF) == idToPocket)
+ _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00);
}
}
}
@@ -1494,18 +1494,16 @@ void Goblin::swapItems(int16 indexToPick, int16 idToPick) {
if (_itemByteFlag == 0) {
for (y = 0; y < _vm->_map->_mapHeight; y++) {
for (x = 0; x < _vm->_map->_mapWidth; x++) {
- if ((_vm->_map->_itemsMap[y][x] & 0xFF) == idToPick)
- _vm->_map->_itemsMap[y][x] =
- (_vm->_map->_itemsMap[y][x] & 0xFF00) + idToPlace;
+ if ((_vm->_map->getItem(x, y) & 0xFF) == idToPick)
+ _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF00) + idToPlace);
}
}
} else {
for (y = 0; y < _vm->_map->_mapHeight; y++) {
for (x = 0; x < _vm->_map->_mapWidth; x++) {
- if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == idToPick)
- _vm->_map->_itemsMap[y][x] =
- (_vm->_map->_itemsMap[y][x] & 0xFF) + (idToPlace << 8);
+ if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == idToPick)
+ _vm->_map->setItem(x, y, (_vm->_map->getItem(x, y) & 0xFF) + (idToPlace << 8));
}
}
}
diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp
index 02e7f99cbd..4973bd756d 100644
--- a/engines/gob/inter.cpp
+++ b/engines/gob/inter.cpp
@@ -259,7 +259,7 @@ void Inter::funcBlock(int16 retFlag) {
if (executeFuncOpcode(cmd2, cmd, params))
return;
- if (_vm->_quitRequested)
+ if (_vm->quit())
break;
if (_break) {
@@ -279,7 +279,7 @@ void Inter::funcBlock(int16 retFlag) {
void Inter::callSub(int16 retFlag) {
byte block;
- while (!_vm->_quitRequested && _vm->_global->_inter_execPtr &&
+ while (!_vm->quit() && _vm->_global->_inter_execPtr &&
(_vm->_global->_inter_execPtr != _vm->_game->_totFileData)) {
block = *_vm->_global->_inter_execPtr;
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index b684be6c07..fe31722c6c 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -529,6 +529,102 @@ protected:
void o4_playVmdOrMusic();
};
+class Inter_v5 : public Inter_v4 {
+public:
+ Inter_v5(GobEngine *vm);
+ virtual ~Inter_v5() {}
+
+protected:
+ typedef void (Inter_v5::*OpcodeDrawProcV5)();
+ typedef bool (Inter_v5::*OpcodeFuncProcV5)(OpFuncParams &);
+ typedef void (Inter_v5::*OpcodeGoblinProcV5)(OpGobParams &);
+ struct OpcodeDrawEntryV5 {
+ OpcodeDrawProcV5 proc;
+ const char *desc;
+ };
+ struct OpcodeFuncEntryV5 {
+ OpcodeFuncProcV5 proc;
+ const char *desc;
+ };
+ struct OpcodeGoblinEntryV5 {
+ OpcodeGoblinProcV5 proc;
+ const char *desc;
+ };
+ const OpcodeDrawEntryV5 *_opcodesDrawV5;
+ const OpcodeFuncEntryV5 *_opcodesFuncV5;
+ const OpcodeGoblinEntryV5 *_opcodesGoblinV5;
+ static const int _goblinFuncLookUp[][2];
+
+ virtual void setupOpcodes();
+ virtual void executeDrawOpcode(byte i);
+ virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams &params);
+ virtual void executeGoblinOpcode(int i, OpGobParams &params);
+ virtual const char *getOpcodeDrawDesc(byte i);
+ virtual const char *getOpcodeFuncDesc(byte i, byte j);
+ virtual const char *getOpcodeGoblinDesc(int i);
+
+ byte _byte_8AA14;
+
+ void o5_deleteFile();
+
+ bool o5_istrlen(OpFuncParams &params);
+
+ void o5_spaceShooter(OpGobParams &params);
+ void o5_getSystemCDSpeed(OpGobParams &params);
+ void o5_getSystemRAM(OpGobParams &params);
+ void o5_getSystemCPUSpeed(OpGobParams &params);
+ void o5_getSystemDrawSpeed(OpGobParams &params);
+ void o5_totalSystemSpecs(OpGobParams &params);
+ void o5_saveSystemSpecs(OpGobParams &params);
+ void o5_loadSystemSpecs(OpGobParams &params);
+
+ void o5_gob92(OpGobParams &params);
+ void o5_gob95(OpGobParams &params);
+ void o5_gob96(OpGobParams &params);
+ void o5_gob97(OpGobParams &params);
+ void o5_gob98(OpGobParams &params);
+ void o5_gob100(OpGobParams &params);
+ void o5_gob200(OpGobParams &params);
+};
+
+class Inter_v6 : public Inter_v5 {
+public:
+ Inter_v6(GobEngine *vm);
+ virtual ~Inter_v6() {}
+
+protected:
+ typedef void (Inter_v6::*OpcodeDrawProcV6)();
+ typedef bool (Inter_v6::*OpcodeFuncProcV6)(OpFuncParams &);
+ typedef void (Inter_v6::*OpcodeGoblinProcV6)(OpGobParams &);
+ struct OpcodeDrawEntryV6 {
+ OpcodeDrawProcV6 proc;
+ const char *desc;
+ };
+ struct OpcodeFuncEntryV6 {
+ OpcodeFuncProcV6 proc;
+ const char *desc;
+ };
+ struct OpcodeGoblinEntryV6 {
+ OpcodeGoblinProcV6 proc;
+ const char *desc;
+ };
+ const OpcodeDrawEntryV6 *_opcodesDrawV6;
+ const OpcodeFuncEntryV6 *_opcodesFuncV6;
+ const OpcodeGoblinEntryV6 *_opcodesGoblinV6;
+ static const int _goblinFuncLookUp[][2];
+
+ virtual void setupOpcodes();
+ virtual void executeDrawOpcode(byte i);
+ virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams &params);
+ virtual void executeGoblinOpcode(int i, OpGobParams &params);
+ virtual const char *getOpcodeDrawDesc(byte i);
+ virtual const char *getOpcodeFuncDesc(byte i, byte j);
+ virtual const char *getOpcodeGoblinDesc(int i);
+
+ bool o6_loadCursor(OpFuncParams &params);
+ bool o6_evaluateStore(OpFuncParams &params);
+};
+
} // End of namespace Gob
#endif // GOB_INTER_H
diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp
index d493fb00d3..d23841efd6 100644
--- a/engines/gob/inter_bargon.cpp
+++ b/engines/gob/inter_bargon.cpp
@@ -750,7 +750,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams &params) {
for (i = 320; i >= 0; i--) {
_vm->_util->setScrollOffset(i, 0);
if ((_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B) ||
- _vm->_quitRequested) {
+ _vm->quit()) {
_vm->_palAnim->fade(0, -2, 0);
_vm->_video->clearSurf(_vm->_draw->_frontSurface);
memset((char *) _vm->_draw->_vgaPalette, 0, 768);
@@ -760,7 +760,7 @@ void Inter_Bargon::oBargon_intro2(OpGobParams &params) {
break;
}
}
- if (!_vm->_quitRequested)
+ if (!_vm->quit())
_vm->_util->setScrollOffset(0, 0);
surface = 0;
if (VAR(57) == ((uint32) -1))
@@ -799,7 +799,7 @@ void Inter_Bargon::oBargon_intro3(OpGobParams &params) {
_vm->_util->longDelay(_vm->_util->getRandom(200));
}
if ((_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B) ||
- _vm->_quitRequested) {
+ _vm->quit()) {
_vm->_sound->blasterStop(10);
_vm->_palAnim->fade(0, -2, 0);
_vm->_video->clearSurf(_vm->_draw->_frontSurface);
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
index 865d188a2e..1e01cd9048 100644
--- a/engines/gob/inter_v1.cpp
+++ b/engines/gob/inter_v1.cpp
@@ -1234,7 +1234,7 @@ bool Inter_v1::o1_repeatUntil(OpFuncParams &params) {
funcBlock(1);
_vm->_global->_inter_execPtr = blockPtr + size + 1;
flag = evalBoolResult();
- } while (!flag && !_break && !_terminate && !_vm->_quitRequested);
+ } while (!flag && !_break && !_terminate && !_vm->quit());
_nestLevel[0]--;
@@ -1269,7 +1269,7 @@ bool Inter_v1::o1_whileDo(OpFuncParams &params) {
} else
_vm->_global->_inter_execPtr += size;
- if (_break || _terminate || _vm->_quitRequested) {
+ if (_break || _terminate || _vm->quit()) {
_vm->_global->_inter_execPtr = blockPtr;
_vm->_global->_inter_execPtr += size;
break;
@@ -2443,10 +2443,10 @@ void Inter_v1::o1_getItem(OpGobParams &params) {
int16 xPos = load16();
int16 yPos = load16();
- if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0)
- params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8);
+ if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0)
+ params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8);
else
- params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos];
+ params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos);
}
void Inter_v1::o1_manipulateMapIndirect(OpGobParams &params) {
@@ -2468,10 +2468,10 @@ void Inter_v1::o1_getItemIndirect(OpGobParams &params) {
xPos = VAR(xPos);
yPos = VAR(yPos);
- if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0)
- params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8);
+ if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0)
+ params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8);
else
- params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos];
+ params.retVarPtr = (uint32) _vm->_map->getItem(xPos, yPos);
}
void Inter_v1::o1_setPassMap(OpGobParams &params) {
@@ -3025,88 +3025,88 @@ void Inter_v1::animPalette() {
void Inter_v1::manipulateMap(int16 xPos, int16 yPos, int16 item) {
for (int y = 0; y < _vm->_map->_mapHeight; y++) {
for (int x = 0; x < _vm->_map->_mapWidth; x++) {
- if ((_vm->_map->_itemsMap[y][x] & 0xFF) == item)
- _vm->_map->_itemsMap[y][x] &= 0xFF00;
- else if (((_vm->_map->_itemsMap[y][x] & 0xFF00) >> 8) == item)
- _vm->_map->_itemsMap[y][x] &= 0xFF;
+ if ((_vm->_map->getItem(x, y) & 0xFF) == item)
+ _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF00);
+ else if (((_vm->_map->getItem(x, y) & 0xFF00) >> 8) == item)
+ _vm->_map->setItem(x, y, _vm->_map->getItem(x, y) & 0xFF);
}
}
if (xPos < _vm->_map->_mapWidth - 1) {
if (yPos > 0) {
- if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) ||
- ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0) ||
- ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0) ||
- ((_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) != 0)) {
+ if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) ||
+ ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0) ||
+ ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0) ||
+ ((_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) != 0)) {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item;
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item);
- _vm->_map->_itemsMap[yPos - 1][xPos] =
- (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item;
+ _vm->_map->setItem(xPos, yPos - 1,
+ (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item);
- _vm->_map->_itemsMap[yPos][xPos + 1] =
- (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item;
+ _vm->_map->setItem(xPos + 1, yPos,
+ (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item);
- _vm->_map->_itemsMap[yPos - 1][xPos + 1] =
- (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF00) + item;
+ _vm->_map->setItem(xPos + 1, yPos - 1,
+ (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF00) + item);
} else {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8));
- _vm->_map->_itemsMap[yPos - 1][xPos] =
- (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos - 1,
+ (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8));
- _vm->_map->_itemsMap[yPos][xPos + 1] =
- (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos + 1, yPos,
+ (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8));
- _vm->_map->_itemsMap[yPos - 1][xPos + 1] =
- (_vm->_map->_itemsMap[yPos - 1][xPos + 1] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos + 1, yPos - 1,
+ (_vm->_map->getItem(xPos + 1, yPos - 1) & 0xFF) + (item << 8));
}
} else {
- if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) ||
- ((_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) != 0)) {
+ if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) ||
+ ((_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) != 0)) {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item;
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item);
- _vm->_map->_itemsMap[yPos][xPos + 1] =
- (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF00) + item;
+ _vm->_map->setItem(xPos + 1, yPos,
+ (_vm->_map->getItem(xPos + 1, yPos) & 0xFF00) + item);
} else {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8));
- _vm->_map->_itemsMap[yPos][xPos + 1] =
- (_vm->_map->_itemsMap[yPos][xPos + 1] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos + 1, yPos,
+ (_vm->_map->getItem(xPos + 1, yPos) & 0xFF) + (item << 8));
}
}
} else {
if (yPos > 0) {
- if (((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) ||
- ((_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) != 0)) {
+ if (((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) ||
+ ((_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) != 0)) {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item;
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item);
- _vm->_map->_itemsMap[yPos - 1][xPos] =
- (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF00) + item;
+ _vm->_map->setItem(xPos, yPos - 1,
+ (_vm->_map->getItem(xPos, yPos - 1) & 0xFF00) + item);
} else {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8));
- _vm->_map->_itemsMap[yPos - 1][xPos] =
- (_vm->_map->_itemsMap[yPos - 1][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos - 1,
+ (_vm->_map->getItem(xPos, yPos - 1) & 0xFF) + (item << 8));
}
} else {
- if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0) {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) + item;
+ if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) {
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF00) + item);
} else {
- _vm->_map->_itemsMap[yPos][xPos] =
- (_vm->_map->_itemsMap[yPos][xPos] & 0xFF) + (item << 8);
+ _vm->_map->setItem(xPos, yPos,
+ (_vm->_map->getItem(xPos, yPos) & 0xFF) + (item << 8));
}
}
}
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index 2f1d2ec0be..b245001653 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -24,6 +24,7 @@
*/
#include "common/endian.h"
+
#include "sound/mixer.h"
#include "sound/mods/infogrames.h"
@@ -1489,7 +1490,7 @@ void Inter_v2::o2_scroll() {
curX = startX;
curY = startY;
- while (!_vm->_quitRequested && ((curX != endX) || (curY != endY))) {
+ while (!_vm->quit() && ((curX != endX) || (curY != endY))) {
curX = stepX > 0 ? MIN(curX + stepX, (int) endX) :
MAX(curX + stepX, (int) endX);
curY = stepY > 0 ? MIN(curY + stepY, (int) endY) :
diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp
new file mode 100644
index 0000000000..6df76bda4a
--- /dev/null
+++ b/engines/gob/inter_v5.cpp
@@ -0,0 +1,1040 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "gob/gob.h"
+#include "gob/inter.h"
+#include "gob/global.h"
+#include "gob/game.h"
+#include "gob/parse.h"
+#include "gob/draw.h"
+
+namespace Gob {
+
+#define OPCODE(x) _OPCODE(Inter_v5, x)
+
+const int Inter_v5::_goblinFuncLookUp[][2] = {
+ {0, 0},
+ {1, 0},
+ {80, 1},
+ {81, 2},
+ {82, 3},
+ {83, 4},
+ {84, 5},
+ {85, 6},
+ {86, 7},
+ {87, 0},
+ {88, 0},
+ {89, 0},
+ {90, 0},
+ {91, 0},
+ {92, 8},
+ {93, 0},
+ {94, 0},
+ {95, 9},
+ {96, 10},
+ {97, 11},
+ {98, 12},
+ {99, 0},
+ {100, 13},
+ {200, 14},
+ {30, 24},
+ {32, 25},
+ {33, 26},
+ {34, 27},
+ {35, 28},
+ {36, 29},
+ {37, 30},
+ {40, 31},
+ {41, 32},
+ {42, 33},
+ {43, 34},
+ {44, 35},
+ {50, 36},
+ {52, 37},
+ {53, 38},
+ {100, 39},
+ {152, 40},
+ {200, 41},
+ {201, 42},
+ {202, 43},
+ {203, 44},
+ {204, 45},
+ {250, 46},
+ {251, 47},
+ {252, 48},
+ {500, 49},
+ {502, 50},
+ {503, 51},
+ {600, 52},
+ {601, 53},
+ {602, 54},
+ {603, 55},
+ {604, 56},
+ {605, 57},
+ {1000, 58},
+ {1001, 59},
+ {1002, 60},
+ {1003, 61},
+ {1004, 62},
+ {1005, 63},
+ {1006, 64},
+ {1008, 65},
+ {1009, 66},
+ {1010, 67},
+ {1011, 68},
+ {1015, 69},
+ {2005, 70}
+};
+
+Inter_v5::Inter_v5(GobEngine *vm) : Inter_v4(vm) {
+ setupOpcodes();
+}
+
+void Inter_v5::setupOpcodes() {
+ static const OpcodeDrawEntryV5 opcodesDraw[256] = {
+ /* 00 */
+ OPCODE(o1_loadMult),
+ OPCODE(o2_playMult),
+ OPCODE(o2_freeMultKeys),
+ {NULL, ""},
+ /* 04 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_initCursor),
+ /* 08 */
+ OPCODE(o1_initCursorAnim),
+ OPCODE(o1_clearCursorAnim),
+ OPCODE(o2_setRenderFlags),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ OPCODE(o1_loadAnim),
+ OPCODE(o1_freeAnim),
+ OPCODE(o1_updateAnim),
+ OPCODE(o2_multSub),
+ /* 14 */
+ OPCODE(o2_initMult),
+ OPCODE(o1_freeMult),
+ OPCODE(o1_animate),
+ OPCODE(o2_loadMultObject),
+ /* 18 */
+ OPCODE(o1_getAnimLayerInfo),
+ OPCODE(o1_getObjAnimSize),
+ OPCODE(o1_loadStatic),
+ OPCODE(o1_freeStatic),
+ /* 1C */
+ OPCODE(o2_renderStatic),
+ OPCODE(o2_loadCurLayer),
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ OPCODE(o2_playCDTrack),
+ OPCODE(o2_waitCDTrackEnd),
+ OPCODE(o2_stopCD),
+ OPCODE(o2_readLIC),
+ /* 24 */
+ OPCODE(o2_freeLIC),
+ OPCODE(o2_getCDTrackPos),
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o2_loadFontToSprite),
+ OPCODE(o1_freeFontToSprite),
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ OPCODE(o2_totSub),
+ OPCODE(o2_switchTotSub),
+ OPCODE(o2_copyVars),
+ OPCODE(o2_pasteVars),
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 48 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 4C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 50 */
+ OPCODE(o2_loadMapObjects),
+ OPCODE(o2_freeGoblins),
+ OPCODE(o2_moveGoblin),
+ OPCODE(o2_writeGoblinPos),
+ /* 54 */
+ OPCODE(o2_stopGoblin),
+ OPCODE(o2_setGoblinState),
+ OPCODE(o2_placeGoblin),
+ {NULL, ""},
+ /* 58 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 5C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 60 */
+ {NULL, ""},
+ OPCODE(o5_deleteFile),
+ {NULL, ""},
+ {NULL, ""},
+ /* 64 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 68 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 6C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 70 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 74 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 78 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 7C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 80 */
+ OPCODE(o4_initScreen),
+ OPCODE(o2_scroll),
+ OPCODE(o2_setScrollOffset),
+ OPCODE(o4_playVmdOrMusic),
+ /* 84 */
+ OPCODE(o2_getImdInfo),
+ OPCODE(o2_openItk),
+ OPCODE(o2_closeItk),
+ OPCODE(o2_setImdFrontSurf),
+ /* 88 */
+ OPCODE(o2_resetImdFrontSurf),
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 8C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 90 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 94 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 98 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 9C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* AC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* BC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* CC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* DC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* EC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* FC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""}
+ };
+
+ static const OpcodeFuncEntryV5 opcodesFunc[80] = {
+ /* 00 */
+ OPCODE(o1_callSub),
+ OPCODE(o1_callSub),
+ OPCODE(o1_printTotText),
+ OPCODE(o1_loadCursor),
+ /* 04 */
+ {NULL, ""},
+ OPCODE(o1_switch),
+ OPCODE(o1_repeatUntil),
+ OPCODE(o1_whileDo),
+ /* 08 */
+ OPCODE(o1_if),
+ OPCODE(o2_evaluateStore),
+ OPCODE(o1_loadSpriteToPos),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ OPCODE(o2_printText),
+ OPCODE(o1_loadTot),
+ OPCODE(o1_palLoad),
+ /* 14 */
+ OPCODE(o1_keyFunc),
+ OPCODE(o1_capturePush),
+ OPCODE(o1_capturePop),
+ OPCODE(o2_animPalInit),
+ /* 18 */
+ OPCODE(o2_addCollision),
+ OPCODE(o2_freeCollision),
+ OPCODE(o3_getTotTextItemPart),
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_drawOperations),
+ OPCODE(o1_setcmdCount),
+ /* 20 */
+ OPCODE(o1_return),
+ OPCODE(o1_renewTimeInVars),
+ OPCODE(o1_speakerOn),
+ OPCODE(o1_speakerOff),
+ /* 24 */
+ OPCODE(o1_putPixel),
+ OPCODE(o2_goblinFunc),
+ OPCODE(o2_createSprite),
+ OPCODE(o1_freeSprite),
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_returnTo),
+ OPCODE(o1_loadSpriteContent),
+ OPCODE(o1_copySprite),
+ OPCODE(o1_fillRect),
+ /* 34 */
+ OPCODE(o1_drawLine),
+ OPCODE(o1_strToLong),
+ OPCODE(o1_invalidate),
+ OPCODE(o1_setBackDelta),
+ /* 38 */
+ OPCODE(o1_playSound),
+ OPCODE(o2_stopSound),
+ OPCODE(o2_loadSound),
+ OPCODE(o1_freeSoundSlot),
+ /* 3C */
+ OPCODE(o1_waitEndPlay),
+ OPCODE(o1_playComposition),
+ OPCODE(o2_getFreeMem),
+ OPCODE(o2_checkData),
+ /* 40 */
+ {NULL, ""},
+ OPCODE(o1_prepareStr),
+ OPCODE(o1_insertStr),
+ OPCODE(o1_cutStr),
+ /* 44 */
+ OPCODE(o1_strstr),
+ OPCODE(o5_istrlen),
+ OPCODE(o1_setMousePos),
+ OPCODE(o1_setFrameRate),
+ /* 48 */
+ OPCODE(o1_animatePalette),
+ OPCODE(o1_animateCursor),
+ OPCODE(o1_blitCursor),
+ OPCODE(o1_loadFont),
+ /* 4C */
+ OPCODE(o1_freeFont),
+ OPCODE(o2_readData),
+ OPCODE(o2_writeData),
+ OPCODE(o1_manageDataFile),
+ };
+
+ static const OpcodeGoblinEntryV5 opcodesGoblin[71] = {
+ /* 00 */
+ OPCODE(o5_spaceShooter),
+ OPCODE(o5_getSystemCDSpeed),
+ OPCODE(o5_getSystemRAM),
+ OPCODE(o5_getSystemCPUSpeed),
+ /* 04 */
+ OPCODE(o5_getSystemDrawSpeed),
+ OPCODE(o5_totalSystemSpecs),
+ OPCODE(o5_saveSystemSpecs),
+ OPCODE(o5_loadSystemSpecs),
+ /* 08 */
+ OPCODE(o5_gob92),
+ OPCODE(o5_gob95),
+ OPCODE(o5_gob96),
+ OPCODE(o5_gob97),
+ /* 0C */
+ OPCODE(o5_gob98),
+ OPCODE(o5_gob100),
+ OPCODE(o5_gob200),
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 14 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 18 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 24 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ };
+
+ _opcodesDrawV5 = opcodesDraw;
+ _opcodesFuncV5 = opcodesFunc;
+ _opcodesGoblinV5 = opcodesGoblin;
+}
+
+void Inter_v5::executeDrawOpcode(byte i) {
+ debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)",
+ i, i, getOpcodeDrawDesc(i));
+
+ OpcodeDrawProcV5 op = _opcodesDrawV5[i].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeDraw: %d", i);
+ else
+ (this->*op) ();
+}
+
+bool Inter_v5::executeFuncOpcode(byte i, byte j, OpFuncParams &params) {
+ debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d",
+ i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile,
+ (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData),
+ (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4));
+
+ if ((i > 4) || (j > 15)) {
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ return false;
+ }
+
+ OpcodeFuncProcV5 op = _opcodesFuncV5[i*16 + j].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ else
+ return (this->*op) (params);
+
+ return false;
+}
+
+void Inter_v5::executeGoblinOpcode(int i, OpGobParams &params) {
+ debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)",
+ i, i, getOpcodeGoblinDesc(i));
+
+ OpcodeGoblinProcV5 op = NULL;
+
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i) {
+ op = _opcodesGoblinV5[_goblinFuncLookUp[j][1]].proc;
+ break;
+ }
+
+ _vm->_global->_inter_execPtr -= 2;
+
+ if (op == NULL) {
+ warning("unimplemented opcodeGoblin: %d", i);
+
+ int16 paramCount = load16();
+ _vm->_global->_inter_execPtr += paramCount * 2;
+ } else {
+ params.extraData = i;
+
+ (this->*op) (params);
+ }
+}
+
+const char *Inter_v5::getOpcodeDrawDesc(byte i) {
+ return _opcodesDrawV5[i].desc;
+}
+
+const char *Inter_v5::getOpcodeFuncDesc(byte i, byte j) {
+ if ((i > 4) || (j > 15))
+ return "";
+
+ return _opcodesFuncV5[i*16 + j].desc;
+}
+
+const char *Inter_v5::getOpcodeGoblinDesc(int i) {
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i)
+ return _opcodesGoblinV5[_goblinFuncLookUp[j][1]].desc;
+ return "";
+}
+
+void Inter_v5::o5_deleteFile() {
+ evalExpr(0);
+
+ warning("Dynasty Stub: deleteFile \"%s\"", _vm->_global->_inter_resStr);
+}
+
+bool Inter_v5::o5_istrlen(OpFuncParams &params) {
+ int16 strVar1, strVar2;
+ int16 len;
+
+ if (*_vm->_global->_inter_execPtr == 0x80) {
+ _vm->_global->_inter_execPtr++;
+
+ strVar1 = _vm->_parse->parseVarIndex();
+ strVar2 = _vm->_parse->parseVarIndex();
+
+ len = _vm->_draw->stringLength(GET_VARO_STR(strVar1), READ_VARO_UINT16(strVar2));
+
+ } else {
+
+ strVar1 = _vm->_parse->parseVarIndex();
+ strVar2 = _vm->_parse->parseVarIndex();
+
+ if (_vm->_global->_language == 10) {
+ // Extra handling for Japanese strings
+
+ for (len = 0; READ_VARO_UINT8(strVar1) != 0; strVar1++, len++)
+ if (READ_VARO_UINT8(strVar1) >= 128)
+ strVar1++;
+
+ } else
+ len = strlen(GET_VARO_STR(strVar1));
+ }
+
+ WRITE_VAR_OFFSET(strVar2, len);
+ return false;
+}
+
+void Inter_v5::o5_spaceShooter(OpGobParams &params) {
+ int16 paramCount = load16();
+
+ warning("Dynasty Stub: Space shooter: %d, %d, %s",
+ params.extraData, paramCount, _vm->_game->_curTotFile);
+
+ if (paramCount < 4) {
+ warning("Space shooter variable counter < 4");
+ _vm->_global->_inter_execPtr += paramCount * 2;
+ return;
+ }
+
+ uint32 var1 = load16() * 4;
+ uint32 var2 = load16() * 4;
+#if 1
+ load16();
+ load16();
+#else
+ uint32 var3 = load16() * 4;
+ uint16 var4 = load16();
+#endif
+
+ if (params.extraData != 0) {
+ WRITE_VARO_UINT32(var1, 0);
+ WRITE_VARO_UINT32(var2, 0);
+ } else {
+ if (paramCount < 5) {
+ warning("Space shooter variable counter < 5");
+ return;
+ }
+
+ _vm->_global->_inter_execPtr += (paramCount - 4) * 2;
+ }
+}
+
+void Inter_v5::o5_getSystemCDSpeed(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 100); // Fudging 100%
+
+ Video::FontDesc *font;
+ if ((font = _vm->_util->loadFont("SPEED.LET"))) {
+ _vm->_draw->drawString("100 %", 402, 89, 112, 144, 0, _vm->_draw->_backSurface, font);
+ _vm->_draw->forceBlit();
+
+ _vm->_util->freeFont(font);
+ }
+}
+
+void Inter_v5::o5_getSystemRAM(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 100); // Fudging 100%
+
+ Video::FontDesc *font;
+ if ((font = _vm->_util->loadFont("SPEED.LET"))) {
+ _vm->_draw->drawString("100 %", 402, 168, 112, 144, 0, _vm->_draw->_backSurface, font);
+ _vm->_draw->forceBlit();
+
+ _vm->_util->freeFont(font);
+ }
+}
+
+void Inter_v5::o5_getSystemCPUSpeed(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 100); // Fudging 100%
+
+ Video::FontDesc *font;
+ if ((font = _vm->_util->loadFont("SPEED.LET"))) {
+ _vm->_draw->drawString("100 %", 402, 248, 112, 144, 0, _vm->_draw->_backSurface, font);
+ _vm->_draw->forceBlit();
+
+ _vm->_util->freeFont(font);
+ }
+}
+
+void Inter_v5::o5_getSystemDrawSpeed(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 100); // Fudging 100%
+
+ Video::FontDesc *font;
+ if ((font = _vm->_util->loadFont("SPEED.LET"))) {
+ _vm->_draw->drawString("100 %", 402, 326, 112, 144, 0, _vm->_draw->_backSurface, font);
+ _vm->_draw->forceBlit();
+
+ _vm->_util->freeFont(font);
+ }
+}
+
+void Inter_v5::o5_totalSystemSpecs(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 100); // Fudging 100%
+
+ Video::FontDesc *font;
+ if ((font = _vm->_util->loadFont("SPEED.LET"))) {
+ _vm->_draw->drawString("100 %", 402, 405, 112, 144, 0, _vm->_draw->_backSurface, font);
+ _vm->_draw->forceBlit();
+
+ _vm->_util->freeFont(font);
+ }
+}
+
+void Inter_v5::o5_saveSystemSpecs(OpGobParams &params) {
+ warning("Dynasty Stub: Saving system specifications");
+
+ _vm->_global->_inter_execPtr += 2;
+
+/*
+ FILE *f = fopen("SAVE\\SPEED.INF", w);
+ fwrite(&_cdSpeed, sizeof(_cdSpeed), 1, f);
+ fwrite(&_ram, sizeof(_ram), 1, f);
+ fwrite(&_cpuSpeed, sizeof(_cpuSpeed), 1, f);
+ fwrite(&_drawSpeed, sizeof(_drawSpeed), 1, f);
+ fwrite(&_total, sizeof(_total), 1, f);
+ fclose(f);
+*/
+}
+
+void Inter_v5::o5_loadSystemSpecs(OpGobParams &params) {
+ warning("Dynasty Stub: Loading system specifications");
+
+ _vm->_global->_inter_execPtr += 2;
+
+/*
+ FILE *f = fopen("SAVE\\SPEED.INF", r);
+ fread(&_cdSpeed, sizeof(_cdSpeed), 1, f);
+ fread(&_ram, sizeof(_ram), 1, f);
+ fread(&_cpuSpeed, sizeof(_cpuSpeed), 1, f);
+ fread(&_drawSpeed, sizeof(_drawSpeed), 1, f);
+ fread(&_total, sizeof(_total), 1, f);
+ fclose(f);
+*/
+
+/*
+ // Calculating whether speed throttling is necessary?
+
+ var_E = MAX(_cdSpeed, 150);
+ var_E += (_ram << 3);
+ var_E += (_cpuSpeed << 3);
+ var_E /= 17;
+
+ byte_8A61E = (var_E > 81) ? 1 : 0;
+ byte_8A5E0 = (_total >= 95) ? 1 : 0;
+
+ if (byte_8A5E0 == 1) {
+ word_8AEE2 = 100;
+ byte_8AEE4 = 1;
+ byte_8AEE5 = 1;
+ word_8AEE6 = 0;
+ } else {
+ word_8AEE2 = 0;
+ byte_8AEE4 = 0;
+ byte_8AEE5 = 0;
+ word_8AEE6 = 40;
+ }
+*/
+}
+
+void Inter_v5::o5_gob92(OpGobParams &params) {
+ warning("Dynasty Stub: GobFunc 92");
+
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_86B9E)) */);
+}
+
+void Inter_v5::o5_gob95(OpGobParams &params) {
+ warning("Dynasty Stub: GobFunc 95");
+
+ _vm->_global->_inter_execPtr += 2;
+
+ WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE6)) */);
+ WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE5)) */);
+ WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) byte_8AEE4)) */);
+ WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) word_8AEE2)) */);
+}
+
+void Inter_v5::o5_gob96(OpGobParams &params) {
+ int16 word_8AEE6, word_85B50, word_8AEE2;
+ byte byte_8AEE5, byte_8AEE4;
+
+ _vm->_global->_inter_execPtr += 2;
+
+ word_8AEE6 = word_85B50 = READ_VAR_UINT16(load16());
+ byte_8AEE5 = READ_VAR_UINT8(load16());
+ byte_8AEE4 = READ_VAR_UINT8(load16());
+ word_8AEE2 = READ_VAR_UINT16(load16());
+
+ warning("Dynasty Stub: GobFunc 96: %d, %d, %d, %d",
+ word_8AEE6, byte_8AEE5, byte_8AEE4, word_8AEE2);
+
+ // .--- sub_194B0 ---
+
+ int16 word_8A8F0, word_8A8F2, word_8A8F4, word_8A8F6, word_8A8F8, word_8A8FA;
+
+ int16 word_8A62C = 1;
+ int16 word_8A63C, word_8A640, word_8B464, word_8B466;
+
+ byte byte_8A62E;
+
+ int16 var_2, var_4;
+
+ var_2 = word_85B50 + 31;
+ word_8A8F0 = word_8A8F2 = var_2;
+ word_8A8F4 = word_85B50;
+
+ var_4 = 315 - word_85B50;
+ word_8A8F6 = word_8A8F8 = var_4;
+
+ word_8A8FA = 479 - word_85B50;
+
+ if (word_8A62C == 0) {
+ word_8A63C = word_8A8F0;
+ word_8A640 = word_8A8F6;
+ word_8B464 = word_8A8F0;
+ word_8B466 = word_8A8F6;
+ } else if (word_8A62C == 1) {
+ word_8A63C = word_85B50;
+ word_8A640 = word_8A8FA;
+ word_8B464 = word_85B50;
+ word_8B466 = word_8A8FA;
+ } else if (word_8A62C == 2) {
+ word_8A63C = word_8A8F4;
+ word_8A640 = word_8A8FA;
+ word_8B464 = word_8A8F4;
+ word_8B466 = word_8A8FA;
+ } else if (word_8A62C == 3) {
+ word_8A63C = word_8A8F4;
+ word_8A640 = word_8A8FA;
+ word_8B464 = word_8A8F4;
+ word_8B466 = word_8A8FA;
+ } else if (word_8A62C == 4) {
+ word_8A63C = word_8A8F4;
+ word_8A640 = word_8A8FA;
+ word_8B464 = word_8A8F4;
+ word_8B466 = word_8A8FA;
+ }
+
+ byte_8A62E = 1;
+
+// '--- ---
+
+}
+
+void Inter_v5::o5_gob97(OpGobParams &params) {
+ _byte_8AA14 = 1;
+
+ _vm->_global->_inter_execPtr += 2;
+}
+
+void Inter_v5::o5_gob98(OpGobParams &params) {
+ _byte_8AA14 = 0;
+
+ _vm->_global->_inter_execPtr += 2;
+}
+
+void Inter_v5::o5_gob100(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ uint16 var1 = READ_VAR_UINT16(load16());
+ uint16 var2 = READ_VAR_UINT16(load16());
+ uint16 var3 = READ_VAR_UINT16(load16());
+ uint16 var4 = READ_VAR_UINT16(load16());
+
+ warning("Dynasty Stub: GobFunc 100: %d, %d, %d, %d", var1, var2, var3, var4);
+
+ var3 = (var3 + var1) - 1;
+ var4 = (var4 + var2) - 1;
+}
+
+void Inter_v5::o5_gob200(OpGobParams &params) {
+ _vm->_global->_inter_execPtr += 2;
+
+ uint16 var1 = load16(); // index into the spritesArray
+ uint16 var2 = load16();
+ uint16 var3 = load16();
+
+ warning("Dynasty Stub: GobFunc 200: %d, %d, %d", var1, var2, var3);
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp
new file mode 100644
index 0000000000..d27bcc64b5
--- /dev/null
+++ b/engines/gob/inter_v6.cpp
@@ -0,0 +1,866 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "gob/gob.h"
+#include "gob/inter.h"
+#include "gob/global.h"
+#include "gob/game.h"
+#include "gob/parse.h"
+#include "gob/draw.h"
+
+namespace Gob {
+
+#define OPCODE(x) _OPCODE(Inter_v6, x)
+
+const int Inter_v6::_goblinFuncLookUp[][2] = {
+ {0, 0},
+ {1, 0},
+ {80, 1},
+ {81, 2},
+ {82, 3},
+ {83, 4},
+ {84, 5},
+ {85, 6},
+ {86, 7},
+ {87, 0},
+ {88, 0},
+ {89, 0},
+ {90, 0},
+ {91, 0},
+ {92, 8},
+ {93, 0},
+ {94, 0},
+ {95, 9},
+ {96, 10},
+ {97, 11},
+ {98, 12},
+ {99, 0},
+ {100, 13},
+ {200, 14},
+ {30, 24},
+ {32, 25},
+ {33, 26},
+ {34, 27},
+ {35, 28},
+ {36, 29},
+ {37, 30},
+ {40, 31},
+ {41, 32},
+ {42, 33},
+ {43, 34},
+ {44, 35},
+ {50, 36},
+ {52, 37},
+ {53, 38},
+ {100, 39},
+ {152, 40},
+ {200, 41},
+ {201, 42},
+ {202, 43},
+ {203, 44},
+ {204, 45},
+ {250, 46},
+ {251, 47},
+ {252, 48},
+ {500, 49},
+ {502, 50},
+ {503, 51},
+ {600, 52},
+ {601, 53},
+ {602, 54},
+ {603, 55},
+ {604, 56},
+ {605, 57},
+ {1000, 58},
+ {1001, 59},
+ {1002, 60},
+ {1003, 61},
+ {1004, 62},
+ {1005, 63},
+ {1006, 64},
+ {1008, 65},
+ {1009, 66},
+ {1010, 67},
+ {1011, 68},
+ {1015, 69},
+ {2005, 70}
+};
+
+Inter_v6::Inter_v6(GobEngine *vm) : Inter_v5(vm) {
+ setupOpcodes();
+}
+
+void Inter_v6::setupOpcodes() {
+ static const OpcodeDrawEntryV6 opcodesDraw[256] = {
+ /* 00 */
+ OPCODE(o1_loadMult),
+ OPCODE(o2_playMult),
+ OPCODE(o2_freeMultKeys),
+ {NULL, ""},
+ /* 04 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_initCursor),
+ /* 08 */
+ OPCODE(o1_initCursorAnim),
+ OPCODE(o1_clearCursorAnim),
+ OPCODE(o2_setRenderFlags),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ OPCODE(o1_loadAnim),
+ OPCODE(o1_freeAnim),
+ OPCODE(o1_updateAnim),
+ OPCODE(o2_multSub),
+ /* 14 */
+ OPCODE(o2_initMult),
+ OPCODE(o1_freeMult),
+ OPCODE(o1_animate),
+ OPCODE(o2_loadMultObject),
+ /* 18 */
+ OPCODE(o1_getAnimLayerInfo),
+ OPCODE(o1_getObjAnimSize),
+ OPCODE(o1_loadStatic),
+ OPCODE(o1_freeStatic),
+ /* 1C */
+ OPCODE(o2_renderStatic),
+ OPCODE(o2_loadCurLayer),
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ OPCODE(o2_playCDTrack),
+ OPCODE(o2_waitCDTrackEnd),
+ OPCODE(o2_stopCD),
+ OPCODE(o2_readLIC),
+ /* 24 */
+ OPCODE(o2_freeLIC),
+ OPCODE(o2_getCDTrackPos),
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o2_loadFontToSprite),
+ OPCODE(o1_freeFontToSprite),
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ OPCODE(o2_totSub),
+ OPCODE(o2_switchTotSub),
+ OPCODE(o2_copyVars),
+ OPCODE(o2_pasteVars),
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 48 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 4C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 50 */
+ OPCODE(o2_loadMapObjects),
+ OPCODE(o2_freeGoblins),
+ OPCODE(o2_moveGoblin),
+ OPCODE(o2_writeGoblinPos),
+ /* 54 */
+ OPCODE(o2_stopGoblin),
+ OPCODE(o2_setGoblinState),
+ OPCODE(o2_placeGoblin),
+ {NULL, ""},
+ /* 58 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 5C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 60 */
+ {NULL, ""},
+ OPCODE(o5_deleteFile),
+ {NULL, ""},
+ {NULL, ""},
+ /* 64 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 68 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 6C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 70 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 74 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 78 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 7C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 80 */
+ OPCODE(o4_initScreen),
+ OPCODE(o2_scroll),
+ OPCODE(o2_setScrollOffset),
+ OPCODE(o4_playVmdOrMusic),
+ /* 84 */
+ OPCODE(o2_getImdInfo),
+ OPCODE(o2_openItk),
+ OPCODE(o2_closeItk),
+ OPCODE(o2_setImdFrontSurf),
+ /* 88 */
+ OPCODE(o2_resetImdFrontSurf),
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 8C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 90 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 94 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 98 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 9C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* A8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* AC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* B8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* BC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* C8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* CC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* D8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* DC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* E8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* EC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F0 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F4 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* F8 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* FC */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""}
+ };
+
+ static const OpcodeFuncEntryV6 opcodesFunc[80] = {
+ /* 00 */
+ OPCODE(o1_callSub),
+ OPCODE(o1_callSub),
+ OPCODE(o1_printTotText),
+ OPCODE(o6_loadCursor),
+ /* 04 */
+ {NULL, ""},
+ OPCODE(o1_switch),
+ OPCODE(o1_repeatUntil),
+ OPCODE(o1_whileDo),
+ /* 08 */
+ OPCODE(o1_if),
+ OPCODE(o6_evaluateStore),
+ OPCODE(o1_loadSpriteToPos),
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ OPCODE(o2_printText),
+ OPCODE(o1_loadTot),
+ OPCODE(o1_palLoad),
+ /* 14 */
+ OPCODE(o1_keyFunc),
+ OPCODE(o1_capturePush),
+ OPCODE(o1_capturePop),
+ OPCODE(o2_animPalInit),
+ /* 18 */
+ OPCODE(o2_addCollision),
+ OPCODE(o2_freeCollision),
+ OPCODE(o3_getTotTextItemPart),
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ OPCODE(o1_drawOperations),
+ OPCODE(o1_setcmdCount),
+ /* 20 */
+ OPCODE(o1_return),
+ OPCODE(o1_renewTimeInVars),
+ OPCODE(o1_speakerOn),
+ OPCODE(o1_speakerOff),
+ /* 24 */
+ OPCODE(o1_putPixel),
+ OPCODE(o2_goblinFunc),
+ OPCODE(o2_createSprite),
+ OPCODE(o1_freeSprite),
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ OPCODE(o1_returnTo),
+ OPCODE(o1_loadSpriteContent),
+ OPCODE(o1_copySprite),
+ OPCODE(o1_fillRect),
+ /* 34 */
+ OPCODE(o1_drawLine),
+ OPCODE(o1_strToLong),
+ OPCODE(o1_invalidate),
+ OPCODE(o1_setBackDelta),
+ /* 38 */
+ OPCODE(o1_playSound),
+ OPCODE(o2_stopSound),
+ OPCODE(o2_loadSound),
+ OPCODE(o1_freeSoundSlot),
+ /* 3C */
+ OPCODE(o1_waitEndPlay),
+ OPCODE(o1_playComposition),
+ OPCODE(o2_getFreeMem),
+ OPCODE(o2_checkData),
+ /* 40 */
+ {NULL, ""},
+ OPCODE(o1_prepareStr),
+ OPCODE(o1_insertStr),
+ OPCODE(o1_cutStr),
+ /* 44 */
+ OPCODE(o1_strstr),
+ OPCODE(o5_istrlen),
+ OPCODE(o1_setMousePos),
+ OPCODE(o1_setFrameRate),
+ /* 48 */
+ OPCODE(o1_animatePalette),
+ OPCODE(o1_animateCursor),
+ OPCODE(o1_blitCursor),
+ OPCODE(o1_loadFont),
+ /* 4C */
+ OPCODE(o1_freeFont),
+ OPCODE(o2_readData),
+ OPCODE(o2_writeData),
+ OPCODE(o1_manageDataFile),
+ };
+
+ static const OpcodeGoblinEntryV6 opcodesGoblin[71] = {
+ /* 00 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 04 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 08 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 0C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 10 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 14 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 18 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 1C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 20 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 24 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 28 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 2C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 30 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 34 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 38 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 3C */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 40 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ /* 44 */
+ {NULL, ""},
+ {NULL, ""},
+ {NULL, ""},
+ };
+
+ _opcodesDrawV6 = opcodesDraw;
+ _opcodesFuncV6 = opcodesFunc;
+ _opcodesGoblinV6 = opcodesGoblin;
+}
+
+void Inter_v6::executeDrawOpcode(byte i) {
+ debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)",
+ i, i, getOpcodeDrawDesc(i));
+
+ OpcodeDrawProcV6 op = _opcodesDrawV6[i].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeDraw: %d", i);
+ else
+ (this->*op) ();
+}
+
+bool Inter_v6::executeFuncOpcode(byte i, byte j, OpFuncParams &params) {
+ debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d",
+ i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile,
+ (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData),
+ (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4));
+
+ if ((i > 4) || (j > 15)) {
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ return false;
+ }
+
+ OpcodeFuncProcV6 op = _opcodesFuncV6[i*16 + j].proc;
+
+ if (op == NULL)
+ warning("unimplemented opcodeFunc: %d.%d", i, j);
+ else
+ return (this->*op) (params);
+
+ return false;
+}
+
+void Inter_v6::executeGoblinOpcode(int i, OpGobParams &params) {
+ debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)",
+ i, i, getOpcodeGoblinDesc(i));
+
+ OpcodeGoblinProcV6 op = NULL;
+
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i) {
+ op = _opcodesGoblinV6[_goblinFuncLookUp[j][1]].proc;
+ break;
+ }
+
+ _vm->_global->_inter_execPtr -= 2;
+
+ if (op == NULL) {
+ warning("unimplemented opcodeGoblin: %d", i);
+
+ int16 paramCount = load16();
+ _vm->_global->_inter_execPtr += paramCount * 2;
+ } else {
+ params.extraData = i;
+
+ (this->*op) (params);
+ }
+}
+
+const char *Inter_v6::getOpcodeDrawDesc(byte i) {
+ return _opcodesDrawV6[i].desc;
+}
+
+const char *Inter_v6::getOpcodeFuncDesc(byte i, byte j) {
+ if ((i > 4) || (j > 15))
+ return "";
+
+ return _opcodesFuncV6[i*16 + j].desc;
+}
+
+const char *Inter_v6::getOpcodeGoblinDesc(int i) {
+ for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
+ if (_goblinFuncLookUp[j][0] == i)
+ return _opcodesGoblinV6[_goblinFuncLookUp[j][1]].desc;
+ return "";
+}
+
+bool Inter_v6::o6_loadCursor(OpFuncParams &params) {
+ Game::TotResItem *itemPtr;
+ int16 width, height;
+ byte *dataBuf;
+ int32 offset;
+ int16 id;
+ int8 index;
+
+ id = load16();
+
+ if (id == -1) {
+ byte str[10];
+
+ for (int i = 0; i < 9; i++)
+ str[i] = *_vm->_global->_inter_execPtr++;
+
+ str[9] = '\0';
+
+ uint16 var1 = load16();
+ int8 var2 = *_vm->_global->_inter_execPtr++;
+
+ warning("Urban Stub: loadCursor %d: \"%s\", %d, %d", id, str, var1, var2);
+
+ } else if (id == -2) {
+
+ uint16 var1 = load16();
+ uint16 var2 = load16();
+ int8 var3 = *_vm->_global->_inter_execPtr++;
+
+ warning("Urban Stub: loadCursor %d: %d, %d, %d", id, var1, var2, var3);
+
+ } else {
+ index = (int8) *_vm->_global->_inter_execPtr++;
+
+ if ((index * _vm->_draw->_cursorWidth) >= _vm->_draw->_cursorSprites->getWidth())
+ return false;
+
+ itemPtr = &_vm->_game->_totResourceTable->items[id];
+ offset = itemPtr->offset;
+
+ if (offset < 0) {
+ offset = (-offset - 1) * 4;
+ dataBuf = _vm->_game->_imFileData +
+ (int32) READ_LE_UINT32(_vm->_game->_imFileData + offset);
+ } else
+ dataBuf = _vm->_game->_totResourceTable->dataPtr + szGame_TotResTable +
+ szGame_TotResItem * _vm->_game->_totResourceTable->itemsCount +
+ offset;
+
+ width = itemPtr->width;
+ height = itemPtr->height;
+
+ _vm->_video->fillRect(_vm->_draw->_cursorSprites,
+ index * _vm->_draw->_cursorWidth, 0,
+ index * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1,
+ _vm->_draw->_cursorHeight - 1, 0);
+
+ _vm->_video->drawPackedSprite(dataBuf, width, height,
+ index * _vm->_draw->_cursorWidth, 0, 0, _vm->_draw->_cursorSprites);
+ _vm->_draw->_cursorAnimLow[index] = 0;
+ }
+
+ return false;
+}
+
+bool Inter_v6::o6_evaluateStore(OpFuncParams &params) {
+ byte *savedPos;
+ int16 varOff;
+ int16 token;
+ int16 result;
+ byte loopCount;
+ uint16 var_6, var_A;
+
+ varOff = _vm->_parse->parseVarIndex(&var_6, &var_A);
+
+ if (var_6 != 0) {
+ int16 var_4;
+
+ savedPos = _vm->_global->_inter_execPtr;
+
+ var_4 = _vm->_parse->parseVarIndex(&var_6, 0);
+
+ memcpy(_vm->_inter->_variables->getAddressOff8(varOff),
+ _vm->_inter->_variables->getAddressOff8(var_4), var_6 * 4);
+
+ _vm->_global->_inter_execPtr = savedPos;
+ evalExpr(&var_4);
+
+ return false;
+ }
+
+ if (*_vm->_global->_inter_execPtr == 98) {
+ _vm->_global->_inter_execPtr++;
+ loopCount = *_vm->_global->_inter_execPtr++;
+
+ for (int i = 0; i < loopCount; i++) {
+ uint8 c = *_vm->_global->_inter_execPtr++;
+ uint16 n = load16();
+
+ memset(_vm->_inter->_variables->getAddressOff8(varOff), c, n);
+
+ varOff += n;
+ }
+
+ return false;
+
+ } else if (*_vm->_global->_inter_execPtr == 99) {
+ _vm->_global->_inter_execPtr++;
+ loopCount = *_vm->_global->_inter_execPtr++;
+ } else
+ loopCount = 1;
+
+ for (int i = 0; i < loopCount; i++) {
+ token = evalExpr(&result);
+ switch (var_A) {
+ case 16:
+ case 18:
+ WRITE_VARO_UINT8(varOff + i, _vm->_global->_inter_resVal);
+ break;
+
+ case 17:
+ case 27:
+ WRITE_VARO_UINT16(varOff + i * 2, _vm->_global->_inter_resVal);
+ break;
+
+ case 23:
+ case 26:
+ WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal);
+ break;
+
+ case 24:
+ WRITE_VARO_UINT16(varOff + i * 4, _vm->_global->_inter_resVal);
+ break;
+
+ case 25:
+ case 28:
+ if (token == 20)
+ WRITE_VARO_UINT8(varOff, result);
+ else
+ WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr);
+ break;
+ }
+ }
+
+ return false;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp
index 75867aaa6c..bb259800c0 100644
--- a/engines/gob/map.cpp
+++ b/engines/gob/map.cpp
@@ -77,10 +77,10 @@ Map::~Map() {
}
void Map::placeItem(int16 x, int16 y, int16 id) {
- if ((_itemsMap[y][x] & 0xFF00) != 0)
- _itemsMap[y][x] = (_itemsMap[y][x] & 0xFF00) | id;
+ if ((getItem(x, y) & 0xFF00) != 0)
+ setItem(x, y, (getItem(x, y) & 0xFF00) | id);
else
- _itemsMap[y][x] = (_itemsMap[y][x] & 0x00FF) | (id << 8);
+ setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8));
}
enum {
diff --git a/engines/gob/map.h b/engines/gob/map.h
index 8a94de8da9..4a211f205d 100644
--- a/engines/gob/map.h
+++ b/engines/gob/map.h
@@ -101,6 +101,9 @@ public:
void loadMapsInitGobs(void);
+ virtual int16 getItem(int x, int y) = 0;
+ virtual void setItem(int x, int y, int16 item) = 0;
+
virtual int8 getPass(int x, int y, int heightOff = -1) = 0;
virtual void setPass(int x, int y, int8 pass, int heightOff = -1) = 0;
@@ -127,6 +130,23 @@ public:
virtual void findNearestToDest(Mult::Mult_Object *obj);
virtual void optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y);
+ virtual int16 getItem(int x, int y) {
+ assert(_itemsMap);
+
+ x = CLIP<int>(x, 0, _mapWidth - 1);
+ y = CLIP<int>(y, 0, _mapHeight - 1);
+
+ return _itemsMap[y][x];
+ }
+ virtual void setItem(int x, int y, int16 item) {
+ assert(_itemsMap);
+
+ x = CLIP<int>(x, 0, _mapWidth - 1);
+ y = CLIP<int>(y, 0, _mapHeight - 1);
+
+ _itemsMap[y][x] = item;
+ }
+
virtual int8 getPass(int x, int y, int heightOff = -1) {
if (!_passMap)
return 0;
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 45048a0899..3ec542934f 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -30,6 +30,8 @@ MODULE_OBJS := \
inter_bargon.o \
inter_v3.o \
inter_v4.o \
+ inter_v5.o \
+ inter_v6.o \
map.o \
map_v1.o \
map_v2.o \
@@ -53,6 +55,7 @@ MODULE_OBJS := \
video.o \
video_v1.o \
video_v2.o \
+ video_v6.o \
sound/sound.o \
sound/sounddesc.o \
sound/pcspeaker.o \
diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp
index b9373d48b3..a502e92188 100644
--- a/engines/gob/mult.cpp
+++ b/engines/gob/mult.cpp
@@ -209,7 +209,7 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape,
_frame++;
_vm->_util->waitEndFrame();
- } while (!stop && !stopNoClear && !_vm->_quitRequested);
+ } while (!stop && !stopNoClear && !_vm->quit());
if (!stopNoClear) {
if (_animDataAllocated) {
diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp
index 20a81174e5..6bd4ddb625 100644
--- a/engines/gob/mult_v2.cpp
+++ b/engines/gob/mult_v2.cpp
@@ -510,10 +510,11 @@ void Mult_v2::playMultInit() {
if (!_animSurf) {
int16 width, height;
- for (int i = 0; i < _objCount; i++) {
- delete _objects[i].pPosX;
- delete _objects[i].pPosY;
- }
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
delete[] _objects;
diff --git a/engines/gob/palanim.cpp b/engines/gob/palanim.cpp
index 71e73adf53..4f2e921dcb 100644
--- a/engines/gob/palanim.cpp
+++ b/engines/gob/palanim.cpp
@@ -23,6 +23,7 @@
*
*/
+
#include "gob/gob.h"
#include "gob/palanim.h"
#include "gob/global.h"
@@ -131,7 +132,7 @@ void PalAnim::fade(Video::PalDesc *palDesc, int16 fadeV, int16 allColors) {
bool stop;
int16 i;
- if (_vm->_quitRequested)
+ if (_vm->quit())
return;
_fadeValue = (fadeV < 0) ? -fadeV : 2;
diff --git a/engines/gob/parse.h b/engines/gob/parse.h
index 7d451b5f79..15ec78b57f 100644
--- a/engines/gob/parse.h
+++ b/engines/gob/parse.h
@@ -33,7 +33,7 @@ public:
void skipExpr(char stopToken);
void printExpr(char stopToken);
void printVarIndex(void);
- virtual int16 parseVarIndex(void) = 0;
+ virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0) = 0;
virtual int16 parseValExpr(byte stopToken = 99) = 0;
virtual int16 parseExpr(byte stopToken, byte *resultPtr) = 0;
@@ -60,7 +60,7 @@ public:
Parse_v1(GobEngine *vm);
virtual ~Parse_v1() {}
- virtual int16 parseVarIndex(void);
+ virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0);
virtual int16 parseValExpr(byte stopToken = 99);
virtual int16 parseExpr(byte stopToken, byte *resultPtr);
};
@@ -70,7 +70,7 @@ public:
Parse_v2(GobEngine *vm);
virtual ~Parse_v2() {}
- virtual int16 parseVarIndex(void);
+ virtual int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0);
virtual int16 parseValExpr(byte stopToken = 99);
virtual int16 parseExpr(byte stopToken, byte *resultPtr);
};
diff --git a/engines/gob/parse_v1.cpp b/engines/gob/parse_v1.cpp
index 3c5f90c068..ed8868397a 100644
--- a/engines/gob/parse_v1.cpp
+++ b/engines/gob/parse_v1.cpp
@@ -35,7 +35,7 @@ namespace Gob {
Parse_v1::Parse_v1(GobEngine *vm) : Parse(vm) {
}
-int16 Parse_v1::parseVarIndex() {
+int16 Parse_v1::parseVarIndex(uint16 *arg_0, uint16 *arg_4) {
int16 temp2;
byte *arrDesc;
int16 dim;
diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp
index a2e6b8fb37..347a253204 100644
--- a/engines/gob/parse_v2.cpp
+++ b/engines/gob/parse_v2.cpp
@@ -35,7 +35,7 @@ namespace Gob {
Parse_v2::Parse_v2(GobEngine *vm) : Parse_v1(vm) {
}
-int16 Parse_v2::parseVarIndex() {
+int16 Parse_v2::parseVarIndex(uint16 *arg_0, uint16 *arg_4) {
int16 temp2;
byte *arrDesc;
int16 dim;
@@ -44,8 +44,74 @@ int16 Parse_v2::parseVarIndex() {
int16 temp;
int16 offset;
int16 val;
+ uint32 varPos = 0;
operation = *_vm->_global->_inter_execPtr++;
+
+ while ((operation == 14) || (operation == 15)) {
+ if (operation == 14) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ if (arg_0)
+ *arg_0 = READ_LE_UINT16(_vm->_global->_inter_execPtr);
+ if (arg_4)
+ *arg_4 = 14;
+
+ _vm->_global->_inter_execPtr += 2;
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ } else if (operation == 15) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ uint16 var_0C = _vm->_inter->load16();
+ if (arg_0)
+ *arg_0 = var_0C;
+ if (arg_4)
+ *arg_4 = 15;
+
+ uint8 var_A = *_vm->_global->_inter_execPtr++;
+
+ byte *var_12 = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += var_A;
+
+ uint16 var_6 = 0;
+
+ for (int i = 0; i < var_A; i++) {
+ temp2 = parseValExpr(12);
+
+ //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0);
+
+ uint16 ax;
+
+ if (temp2 < 0) {
+ ax = 0;
+ } else if (var_12[i] > temp2) {
+ ax = temp2;
+ } else {
+ ax = var_12[i] - 1;
+ }
+
+ var_6 = var_6 * var_12[i] + ax;
+ }
+
+ varPos += var_6 * var_0C * 4;
+
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ }
+
+ warning("v5+ Stub: parseVarIndex operation %d, offset %d", operation, varPos);
+
+ operation = *_vm->_global->_inter_execPtr++;
+ }
+
+ if (arg_0)
+ *arg_0 = 0;
+ if (arg_4)
+ *arg_4 = operation;
+
debugC(5, kDebugParser, "var parse = %d", operation);
switch (operation) {
case 16:
@@ -62,24 +128,24 @@ int16 Parse_v2::parseVarIndex() {
offset = arrDesc[dim] * offset + temp2;
}
if (operation == 16)
- return temp + offset;
+ return varPos + temp + offset;
if (operation == 26)
- return (temp + offset) * 4;
+ return varPos + (temp + offset) * 4;
if (operation == 27)
- return (temp + offset) * 2;
+ return varPos + (temp + offset) * 2;
temp *= 4;
offset *= 4;
if (*_vm->_global->_inter_execPtr == 13) {
_vm->_global->_inter_execPtr++;
temp += parseValExpr(12);
}
- return offset * _vm->_global->_inter_animDataSize + temp;
+ return varPos + offset * _vm->_global->_inter_animDataSize + temp;
case 17:
- return _vm->_inter->load16() * 2;
+ return varPos + _vm->_inter->load16() * 2;
case 18:
- return _vm->_inter->load16();
+ return varPos + _vm->_inter->load16();
case 23:
case 24:
@@ -93,7 +159,7 @@ int16 Parse_v2::parseVarIndex() {
temp += val;
debugC(5, kDebugParser, "parse subscript = %d", val);
}
- return temp;
+ return varPos + temp;
default:
return 0;
@@ -116,6 +182,7 @@ int16 Parse_v2::parseValExpr(byte stopToken) {
int16 brackPos;
static int16 flag = 0;
int16 oldflag;
+ uint32 varPos = 0;
memset(values, 0, 20 * sizeof(int16));
@@ -130,11 +197,61 @@ int16 Parse_v2::parseValExpr(byte stopToken) {
valPtr = values - 1;
while (1) {
+ operation = *_vm->_global->_inter_execPtr++;
+
+ while ((operation == 14) || (operation == 15)) {
+ if (operation == 14) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ _vm->_global->_inter_execPtr += 2;
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ } else if (operation == 15) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ uint16 var_0C = _vm->_inter->load16();
+ uint8 var_A = *_vm->_global->_inter_execPtr++;
+
+ byte *var_12 = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += var_A;
+
+ uint16 var_6 = 0;
+
+ for (int i = 0; i < var_A; i++) {
+ temp2 = parseValExpr(12);
+
+ //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0);
+
+ uint16 ax;
+
+ if (temp2 < 0) {
+ ax = 0;
+ } else if (var_12[i] > temp2) {
+ ax = temp2;
+ } else {
+ ax = var_12[i] - 1;
+ }
+
+ var_6 = var_6 * var_12[i] + ax;
+ }
+
+ varPos += var_6 * var_0C * 4;
+
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ }
+
+ warning("v5+ Stub: parseValExpr operation %d, offset %d", operation, varPos);
+
+ operation = *_vm->_global->_inter_execPtr++;
+ }
+
stkPos++;
operPtr++;
valPtr++;
- operation = *_vm->_global->_inter_execPtr++;
if ((operation >= 16) && (operation <= 29)) {
*operPtr = 20;
switch (operation) {
@@ -152,29 +269,29 @@ int16 Parse_v2::parseValExpr(byte stopToken) {
offset = arrDesc[dim] * offset + temp2;
}
if (operation == 16)
- *valPtr = (int8) READ_VARO_UINT8(temp + offset);
+ *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset);
else if (operation == 26)
- *valPtr = (uint16) READ_VARO_UINT32(temp * 4 + offset * 4);
+ *valPtr = (uint16) READ_VARO_UINT32(varPos + temp * 4 + offset * 4);
else if (operation == 27)
- *valPtr = READ_VARO_UINT16(temp * 2 + offset * 2);
+ *valPtr = READ_VARO_UINT16(varPos + temp * 2 + offset * 2);
else if (operation == 28) {
_vm->_global->_inter_execPtr++;
temp2 = parseValExpr(12);
- *valPtr = READ_VARO_UINT8(temp * 4 +
+ *valPtr = READ_VARO_UINT8(varPos + temp * 4 +
offset * 4 * _vm->_global->_inter_animDataSize + temp2);
}
break;
case 17:
- *valPtr = READ_VARO_UINT16(_vm->_inter->load16() * 2);
+ *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2);
break;
case 18:
- *valPtr = (int8) READ_VARO_UINT8(_vm->_inter->load16());
+ *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16());
break;
case 19:
- *valPtr = (uint16) READ_LE_UINT32(_vm->_global->_inter_execPtr);
+ *valPtr = (uint16) READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr);
_vm->_global->_inter_execPtr += 4;
break;
@@ -191,14 +308,14 @@ int16 Parse_v2::parseValExpr(byte stopToken) {
break;
case 24:
- *valPtr = READ_VARO_UINT16(_vm->_inter->load16() * 4);
+ *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4);
break;
case 25:
temp = _vm->_inter->load16() * 4;
_vm->_global->_inter_execPtr++;
temp += parseValExpr(12);
- *valPtr = READ_VARO_UINT8(temp);
+ *valPtr = READ_VARO_UINT8(varPos + temp);
break;
case 29:
@@ -373,6 +490,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {
bool var_1A;
int16 stkPos;
int16 brackStart;
+ uint32 varPos = 0;
memset(operStack, 0, 20);
@@ -381,10 +499,61 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {
valPtr = values - 1;
while (1) {
+ operation = *_vm->_global->_inter_execPtr++;
+
+ while ((operation == 14) || (operation == 15)) {
+ if (operation == 14) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ _vm->_global->_inter_execPtr += 2;
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ } else if (operation == 15) {
+ uint16 n = _vm->_inter->load16();
+ varPos += n * 4;
+
+ uint16 var_0C = _vm->_inter->load16();
+ uint8 var_A = *_vm->_global->_inter_execPtr++;
+
+ byte *var_12 = _vm->_global->_inter_execPtr;
+ _vm->_global->_inter_execPtr += var_A;
+
+ uint16 var_6 = 0;
+
+ for (int i = 0; i < var_A; i++) {
+ temp2 = parseValExpr(12);
+
+ //uint16 ax = sub_12063(temp2, var_12[i], varPos, 0);
+
+ uint16 ax;
+
+ if (temp2 < 0) {
+ ax = 0;
+ } else if (var_12[i] > temp2) {
+ ax = temp2;
+ } else {
+ ax = var_12[i] - 1;
+ }
+
+ var_6 = var_6 * var_12[i] + ax;
+ }
+
+ varPos += var_6 * var_0C * 4;
+
+ if (*_vm->_global->_inter_execPtr == 97)
+ _vm->_global->_inter_execPtr++;
+ }
+
+ warning("v5+ Stub: parseExpr operation %d, offset %d", operation, varPos);
+
+ operation = *_vm->_global->_inter_execPtr++;
+ }
+
stkPos++;
operPtr++;
valPtr++;
- operation = *_vm->_global->_inter_execPtr++;
+
if ((operation >= 16) && (operation <= 29)) {
switch (operation) {
case 16:
@@ -402,20 +571,20 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {
offset = offset * arrDescPtr[dim] + temp2;
}
if (operation == 16)
- *valPtr = (int8) READ_VARO_UINT8(temp + offset);
+ *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset);
else if (operation == 26)
- *valPtr = READ_VARO_UINT32(temp * 4 + offset * 4);
+ *valPtr = READ_VARO_UINT32(varPos + temp * 4 + offset * 4);
else if (operation == 27)
- *valPtr = (int16) READ_VARO_UINT16(temp * 2 + offset * 2);
+ *valPtr = (int16) READ_VARO_UINT16(varPos + temp * 2 + offset * 2);
else if (operation == 28) {
*valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(
- temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0),
+ varPos + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0),
kInterVar);
if (*_vm->_global->_inter_execPtr == 13) {
_vm->_global->_inter_execPtr++;
temp2 = parseValExpr(12);
*operPtr = 20;
- *valPtr = READ_VARO_UINT8(temp * 4 +
+ *valPtr = READ_VARO_UINT8(varPos + temp * 4 +
offset * 4 * _vm->_global->_inter_animDataSize + temp2);
}
}
@@ -423,17 +592,17 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {
case 17:
*operPtr = 20;
- *valPtr = (int16) READ_VARO_UINT16(_vm->_inter->load16() * 2);
+ *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2);
break;
case 18:
*operPtr = 20;
- *valPtr = (int8) READ_VARO_UINT8(_vm->_inter->load16());
+ *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16());
break;
case 19:
*operPtr = 20;
- *valPtr = READ_LE_UINT32(_vm->_global->_inter_execPtr);
+ *valPtr = READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr);
_vm->_global->_inter_execPtr += 4;
break;
@@ -461,18 +630,18 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) {
case 24:
*operPtr = 20;
- *valPtr = (int16) READ_VARO_UINT16(_vm->_inter->load16() * 4);
+ *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4);
break;
case 25:
*operPtr = 22;
temp = _vm->_inter->load16() * 4;
- *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp, 0), kInterVar);
+ *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(varPos + temp, 0), kInterVar);
if (*_vm->_global->_inter_execPtr == 13) {
_vm->_global->_inter_execPtr++;
temp += parseValExpr(12);
*operPtr = 20;
- *valPtr = READ_VARO_UINT8(temp);
+ *valPtr = READ_VARO_UINT8(varPos + temp);
}
break;
diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp
index fa9f8ea7a9..e3212ac8ff 100644
--- a/engines/gob/saveload.cpp
+++ b/engines/gob/saveload.cpp
@@ -513,7 +513,7 @@ bool StagedSave::read() {
return false;
}
- uint32 saveSize = getSize();
+ int32 saveSize = getSize();
if (in->size() != saveSize) {
warning("Wrong size (%d != %d)", in->size(), saveSize);
return false;
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 2d2bf8e043..7b93003791 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -369,7 +369,7 @@ void Sound::blasterWaitEndPlay(bool interruptible, bool stopComp) {
if (stopComp)
_blaster->endComposition();
- while (_blaster->isPlaying() && !_vm->_quitRequested) {
+ while (_blaster->isPlaying() && !_vm->quit()) {
if (interruptible && (_vm->_util->checkKey() == 0x11B)) {
WRITE_VAR(57, (uint32) -1);
return;
diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp
index 4987426fe0..fcf19f03dd 100644
--- a/engines/gob/util.cpp
+++ b/engines/gob/util.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/events.h"
#include "gob/gob.h"
#include "gob/util.h"
@@ -72,7 +71,7 @@ void Util::longDelay(uint16 msecs) {
_vm->_video->waitRetrace();
processInput();
delay(15);
- } while (!_vm->_quitRequested &&
+ } while (!_vm->quit() &&
((g_system->getMillis() * _vm->_global->_speedFactor) < time));
}
@@ -118,9 +117,6 @@ void Util::processInput(bool scroll) {
break;
case Common::EVENT_KEYUP:
break;
- case Common::EVENT_QUIT:
- _vm->_quitRequested = true;
- break;
default:
break;
}
@@ -238,7 +234,9 @@ void Util::getMouseState(int16 *pX, int16 *pY, int16 *pButtons) {
}
void Util::setMousePos(int16 x, int16 y) {
- g_system->warpMouse(x + _vm->_video->_screenDeltaX, y + _vm->_video->_screenDeltaY);
+ x = CLIP<int>(x + _vm->_video->_screenDeltaX, 0, _vm->_width - 1);
+ y = CLIP<int>(y + _vm->_video->_screenDeltaY, 0, _vm->_height - 1);
+ g_system->warpMouse(x, y);
}
void Util::waitMouseUp(void) {
diff --git a/engines/gob/video.h b/engines/gob/video.h
index 1338885588..e6baf9a67d 100644
--- a/engines/gob/video.h
+++ b/engines/gob/video.h
@@ -194,6 +194,15 @@ public:
virtual ~Video_v2() {}
};
+class Video_v6 : public Video_v2 {
+public:
+ virtual char spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight,
+ int16 x, int16 y, int16 transp, SurfaceDesc *destDesc);
+
+ Video_v6(GobEngine *vm);
+ virtual ~Video_v6() {}
+};
+
class VideoDriver {
public:
VideoDriver() {}
diff --git a/engines/gob/video_v6.cpp b/engines/gob/video_v6.cpp
new file mode 100644
index 0000000000..434406265e
--- /dev/null
+++ b/engines/gob/video_v6.cpp
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/endian.h"
+
+#include "gob/gob.h"
+#include "gob/video.h"
+
+namespace Gob {
+
+Video_v6::Video_v6(GobEngine *vm) : Video_v2(vm) {
+}
+
+char Video_v6::spriteUncompressor(byte *sprBuf, int16 srcWidth, int16 srcHeight,
+ int16 x, int16 y, int16 transp, SurfaceDesc *destDesc) {
+ if (!destDesc)
+ return 1;
+
+ _vm->validateVideoMode(destDesc->_vidMode);
+
+ if (sprBuf[0] != 1)
+ return 0;
+
+ if (sprBuf[1] != 3)
+ return 0;
+
+ sprBuf += 2;
+
+ srcWidth = READ_LE_UINT16(sprBuf);
+ sprBuf += 2;
+ srcHeight = READ_LE_UINT16(sprBuf);
+ sprBuf += 2;
+
+ if (sprBuf[0] == 0) {
+ SurfaceDesc sourceDesc(0x13, srcWidth, srcHeight, sprBuf + 3);
+ Video::drawSprite(&sourceDesc, destDesc, 0, 0, srcWidth - 1,
+ srcHeight - 1, x, y, transp);
+ return 1;
+ } else {
+ warning("Urban Stub: spriteUncompressor()");
+ return 0;
+ }
+
+ return 1;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index aa47e6cf84..daf7bdd801 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -23,6 +23,7 @@
*
*/
+
#include "gob/videoplayer.h"
#include "gob/global.h"
#include "gob/util.h"
@@ -568,7 +569,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey,
_vm->_util->processInput();
- if (_vm->_quitRequested) {
+ if (_vm->quit()) {
_primaryVideo->getVideo()->disableSound();
return true;
}
diff --git a/engines/igor/parts/part_22.cpp b/engines/igor/parts/part_22.cpp
index 9727ae3e1a..7a7c26d477 100644
--- a/engines/igor/parts/part_22.cpp
+++ b/engines/igor/parts/part_22.cpp
@@ -74,7 +74,9 @@ void IgorEngine::PART_22_ACTION_101() {
void IgorEngine::PART_22_ACTION_102() {
_walkDataCurrentIndex = 0;
_walkCurrentFrame = 1;
- for (int i = 9; i >= 0; --i) {
+ int i = 0;
+
+ for (i = 9; i >= 0; --i) {
WalkData *wd = &_walkData[0];
wd->setPos(138, 123, 1, _walkCurrentFrame);
WalkData::setNextFrame(1, _walkCurrentFrame);
@@ -89,7 +91,7 @@ void IgorEngine::PART_22_ACTION_102() {
moveIgor(wd->posNum, wd->frameNum);
waitForTimer(15);
}
- int i = 16;
+ i = 16;
do {
if (compareGameTick(1, 16)) {
memcpy(_screenTextLayer + (i * 8 + 16) * 320, _screenLayer1 + (128 - i * 8) * 320, (i * 8 + 16) * 320);
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index fce1e93bc2..7a377471c1 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -26,6 +26,7 @@
#include "kyra/kyra_lok.h"
#include "kyra/kyra_hof.h"
#include "kyra/kyra_mr.h"
+#include "kyra/lol.h"
#include "common/config-manager.h"
#include "common/advancedDetector.h"
@@ -55,6 +56,7 @@ namespace {
#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2)
#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA2)
#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, Kyra::GI_KYRA2)
#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, Kyra::GI_KYRA2)
#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2)
#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2)
@@ -64,7 +66,15 @@ namespace {
#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3)
#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3)
+#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_LOL)
+#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_LOL)
+#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_LOL)
+#define LOL_PC98_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_LOL)
+#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_LOL)
+#define LOL_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2)
+
const KYRAGameDescription adGameDescs[] = {
+ /* disable these targets until they get supported
{
{
"kyra1",
@@ -76,6 +86,7 @@ const KYRAGameDescription adGameDescs[] = {
},
KYRA1_FLOPPY_CMP_FLAGS
},
+
{
{
"kyra1",
@@ -87,6 +98,8 @@ const KYRAGameDescription adGameDescs[] = {
},
KYRA1_FLOPPY_CMP_FLAGS
},
+ */
+
{
{
"kyra1",
@@ -207,7 +220,7 @@ const KYRAGameDescription adGameDescs[] = {
{ // FM-Towns version
{
"kyra1",
- 0,
+ "CD",
{
{ "EMC.PAK", 0, "a046bb0b422061aab8e4c4689400343a", -1 },
{ "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 },
@@ -215,14 +228,14 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::EN_ANY,
Common::kPlatformFMTowns,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA1_TOWNS_FLAGS
},
{
{
"kyra1",
- 0,
+ "CD",
{
{ "JMC.PAK", 0, "9c5707a2a478e8167e44283246612d2c", -1 },
{ "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 },
@@ -230,7 +243,7 @@ const KYRAGameDescription adGameDescs[] = {
},
Common::JA_JPN,
Common::kPlatformFMTowns,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA1_TOWNS_SJIS_FLAGS
},
@@ -384,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",
@@ -418,6 +443,77 @@ const KYRAGameDescription adGameDescs[] = {
KYRA2_CD_FLAGS
},
+ // Italian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3"
+ { // CD version
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"),
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+ {
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+ {
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"),
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+
+ {
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "39772ff82e42c4c520050518deb82e64"),
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+
+ {
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "39772ff82e42c4c520050518deb82e64"),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+
+ {
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FATE.PAK", "39772ff82e42c4c520050518deb82e64"),
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
+ },
+
{ // Interactive Demo
{
"kyra2",
@@ -454,11 +550,11 @@ const KYRAGameDescription adGameDescs[] = {
KYRA2_CD_DEMO_FLAGS
},
- { // Non-Interactive Demo
+ { // Non-Interactive Demos
{
"kyra2",
"Demo",
- AD_ENTRY1("GENERAL.PAK", "35825783e5b60755fd520360079f9c15"),
+ AD_ENTRY1("VOC.PAK", "ecb3561b63749158172bf21528cf5f45"),
Common::EN_ANY,
Common::kPlatformPC,
Common::ADGF_DEMO
@@ -469,44 +565,44 @@ const KYRAGameDescription adGameDescs[] = {
{ // FM-Towns
{
"kyra2",
- 0,
+ "CD",
AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
Common::EN_ANY,
Common::kPlatformFMTowns,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA2_TOWNS_FLAGS
},
{
{
"kyra2",
- 0,
+ "CD",
AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
Common::JA_JPN,
Common::kPlatformFMTowns,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA2_TOWNS_SJIS_FLAGS
},
{ // PC-9821
{
"kyra2",
- 0,
+ "CD",
AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
Common::EN_ANY,
Common::kPlatformPC98,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA2_TOWNS_FLAGS
},
{
{
"kyra2",
- 0,
+ "CD",
AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
Common::JA_JPN,
Common::kPlatformPC98,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_CD
},
KYRA2_TOWNS_SJIS_FLAGS
},
@@ -607,6 +703,53 @@ const KYRAGameDescription adGameDescs[] = {
KYRA3_CD_INS_FLAGS
},
+ // Mac version
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "3833ff312757b8e6147f464cca0a6587", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_INS_FLAGS
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "3833ff312757b8e6147f464cca0a6587", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformMacintosh,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_INS_FLAGS
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "3833ff312757b8e6147f464cca0a6587", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformMacintosh,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_INS_FLAGS
+ },
+
// Spanish fan translation, see fr#1994040 "KYRA3: Add support for Spanish fan translation"
{
{
@@ -654,7 +797,7 @@ const KYRAGameDescription adGameDescs[] = {
KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
},
- // Itlian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3"
+ // Italian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3"
{
{
"kyra3",
@@ -700,6 +843,183 @@ const KYRAGameDescription adGameDescs[] = {
},
KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
},
+
+ // Lands of Lore CD
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "9e4bab499b7ea9337b91ac29fcba6d13", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "9e4bab499b7ea9337b91ac29fcba6d13", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "9e4bab499b7ea9337b91ac29fcba6d13", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ 0,
+ {
+ { "WESTWOOD.1", 0, "3c61cb7de5b2ec452f5851f5075207ee", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ LOL_FLOPPY_CMP_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "Extracted",
+ {
+ { "GENERAL.PAK", 0, "996e66e81054d36249907a1d8158da3d", -1 },
+ { "CHAPTER7.PAK", 0, "cabee57f00d6d84b65a732b6868a4959", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ LOL_FLOPPY_FLAGS
+ },
+
+ /* disable these targets until they get supported
+ {
+ {
+ "lol",
+ 0,
+ {
+ { "GENERAL.PAK", 0, "3fe6539b9b09084c0984eaf7170464e9", -1 },
+ { "MUS.PAK", 0, "008dc69d8cbcdb6bae30e270fab26e76", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC98,
+ Common::ADGF_NO_FLAGS
+ },
+ LOL_PC98_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ 0,
+ {
+ { "GENERAL.PAK", 0, "3fe6539b9b09084c0984eaf7170464e9", -1 },
+ { "MUS.PAK", 0, "008dc69d8cbcdb6bae30e270fab26e76", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::JA_JPN,
+ Common::kPlatformPC98,
+ Common::ADGF_NO_FLAGS
+ },
+ LOL_PC98_SJIS_FLAGS
+ },*/
+
+ {
+ {
+ "lol",
+ "Demo",
+ {
+ { "GENERAL.PAK", 0, "e94863d86c4597a2d581d05481c152ba", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ LOL_DEMO_FLAGS
+ },
+
{ AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) }
};
@@ -707,6 +1027,7 @@ const PlainGameDescriptor gameList[] = {
{ "kyra1", "The Legend of Kyrandia" },
{ "kyra2", "The Legend of Kyrandia: The Hand of Fate" },
{ "kyra3", "The Legend of Kyrandia: Malcolm's Revenge" },
+ { "lol", "Lands of Lore: The Throne of Chaos" },
{ 0, 0 }
};
@@ -743,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;
@@ -779,6 +1112,9 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
case Kyra::GI_KYRA3:
*engine = new Kyra::KyraEngine_MR(syst, flags);
break;
+ case Kyra::GI_LOL:
+ *engine = new Kyra::LoLEngine(syst, flags);
+ break;
default:
res = false;
warning("Kyra engine: unknown gameID");
@@ -795,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++) {
@@ -805,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;
}
}
@@ -815,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 35b343fc25..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;
@@ -530,7 +540,7 @@ int GUI_LoK::resumeGame(Button *button) {
void GUI_LoK::setupSavegames(Menu &menu, int num) {
Common::InSaveFile *in;
- static char savenames[5][31];
+ static char savenames[5][35];
uint8 startSlot;
assert(num <= 5);
@@ -549,7 +559,8 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) {
KyraEngine_v1::SaveHeader header;
for (int i = startSlot; i < num && uint(_savegameOffset + i) < _saveSlots.size(); i++) {
if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header))) {
- strncpy(savenames[i], header.description.c_str(), 31);
+ strncpy(savenames[i], header.description.c_str(), ARRAYSIZE(savenames[0]));
+ savenames[i][34] = 0;
menu.item[i].itemString = savenames[i];
menu.item[i].enabled = 1;
menu.item[i].saveSlot = _saveSlots[i + _savegameOffset];
@@ -582,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);
@@ -631,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);
@@ -673,7 +684,7 @@ void GUI_LoK::updateSavegameString() {
length = strlen(_savegameName);
if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127) {
- if (length < 31) {
+ if (length < ARRAYSIZE(_savegameName)-1) {
_savegameName[length] = _keyPressed.ascii;
_savegameName[length+1] = 0;
redrawTextfield();
@@ -719,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();
@@ -735,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;
@@ -795,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);
@@ -861,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 49081c7ae2..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();
@@ -162,7 +164,7 @@ private:
bool _menuRestoreScreen;
uint8 _toplevelMenu;
int _savegameOffset;
- char _savegameName[31];
+ char _savegameName[35];
const char *_specialSavegameString;
Common::KeyState _keyPressed;
int8 _mouseWheel;
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 2819c4f077..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;
@@ -456,6 +457,7 @@ void GUI_v2::setupSavegameNames(Menu &menu, int num) {
for (int i = startSlot; i < num && uint(_savegameOffset + i) < _saveSlots.size(); ++i) {
if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header)) != 0) {
strncpy(getTableString(menu.item[i].itemId), header.description.c_str(), 80);
+ getTableString(menu.item[i].itemId)[79] = 0;
menu.item[i].saveSlot = _saveSlots[i + _savegameOffset];
menu.item[i].enabled = true;
delete in;
@@ -617,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;
@@ -761,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;
@@ -770,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();
}
}
@@ -817,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;
@@ -847,6 +854,7 @@ void GUI_v2::checkTextfieldInput() {
_vm->_mouseX = pos.x;
_vm->_mouseY = pos.y;
_screen->updateScreen();
+ _lastScreenUpdate = now;
} break;
default:
@@ -854,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 161752627b..88861ff905 100644
--- a/engines/kyra/gui_v2.h
+++ b/engines/kyra/gui_v2.h
@@ -188,7 +188,7 @@ protected:
// save menu
bool _noSaveProcess;
int _saveSlot;
- char _saveDescription[0x50];
+ char _saveDescription[0x51];
int saveMenu(Button *caller);
int clickSaveSlot(Button *caller);
@@ -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 879efab86e..76d6f6ea05 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -196,14 +196,18 @@ void KyraEngine_HoF::pauseEngineIntern(bool pause) {
_seqWsaChatTimeout += pausedTime;
_seqWsaChatFrameTimeout += pausedTime;
- for (int x = 0; x < 10; x++) {
- if (_activeText[x].duration != -1)
- _activeText[x].startTime += pausedTime;
+ if (_activeText) {
+ for (int x = 0; x < 10; x++) {
+ if (_activeText[x].duration != -1)
+ _activeText[x].startTime += pausedTime;
+ }
}
- for (int x = 0; x < 8; x++) {
- if (_activeWSA[x].flags != -1)
- _activeWSA[x].nextFrame += pausedTime;
+ if (_activeWSA) {
+ for (int x = 0; x < 8; x++) {
+ if (_activeWSA[x].flags != -1)
+ _activeWSA[x].nextFrame += pausedTime;
+ }
}
_nextIdleAnim += pausedTime;
@@ -230,7 +234,7 @@ int KyraEngine_HoF::init() {
_gui = new GUI_HoF(this);
assert(_gui);
_gui->initStaticData();
- _tim = new TIMInterpreter(this, _system);
+ _tim = new TIMInterpreter(this, _screen, _system);
assert(_tim);
if (_flags.isDemo && !_flags.isTalkie) {
@@ -251,7 +255,7 @@ int KyraEngine_HoF::init() {
_abortIntroFlag = false;
if (_sequenceStrings) {
- for (int i = 0; i < 33; i++)
+ for (int i = 0; i < MIN(33, _sequenceStringsSize); i++)
_sequenceStringsDuration[i] = (int) strlen(_sequenceStrings[i]) * 8;
}
@@ -278,7 +282,10 @@ int KyraEngine_HoF::go() {
seq_showStarcraftLogo();
if (_flags.isDemo && !_flags.isTalkie) {
- seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher);
+ if (_flags.gameID == GI_LOL)
+ seq_playSequences(kSequenceLolDemoScene1, kSequenceLolDemoScene6);
+ else
+ seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher);
_menuChoice = 4;
} else {
seq_playSequences(kSequenceVirgin, kSequenceZanfaun);
@@ -292,13 +299,17 @@ int KyraEngine_HoF::go() {
if (_menuChoice != 4) {
// load just the pak files needed for ingame
_res->loadPakFile(StaticResource::staticDataFilename());
- if (_flags.platform == Common::kPlatformPC && _flags.isTalkie)
- _res->loadFileList("FILEDATA.FDT");
- else
+ if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) {
+ if (!_res->loadFileList("FILEDATA.FDT"))
+ error("couldn't load 'FILEDATA.FDT'");
+ } else {
_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;
@@ -425,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));
}
@@ -443,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();
@@ -1501,15 +1516,19 @@ void KyraEngine_HoF::openTalkFile(int newFile) {
_oldTalkFile = -1;
}
- if (newFile == 0) {
+ if (newFile == 0)
strcpy(talkFilename, "ANYTALK.TLK");
- _res->loadPakFile(talkFilename);
- } else {
+ else
sprintf(talkFilename, "CH%dVOC.TLK", newFile);
- _res->loadPakFile(talkFilename);
- }
_oldTalkFile = newFile;
+
+ if (!_res->loadPakFile(talkFilename)) {
+ if (speechEnabled()) {
+ warning("Couldn't load file '%s' falling back to text only mode", talkFilename);
+ _configVoice = 0;
+ }
+ }
}
void KyraEngine_HoF::snd_playVoiceFile(int id) {
@@ -1545,7 +1564,8 @@ void KyraEngine_HoF::playVoice(int high, int low) {
if (!_flags.isTalkie)
return;
int vocFile = high * 10000 + low * 10;
- snd_playVoiceFile(vocFile);
+ if (speechEnabled())
+ snd_playVoiceFile(vocFile);
}
void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) {
@@ -1564,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 -
@@ -1606,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);
}
@@ -1980,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 866dd55d16..dc4161f0c1 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -97,6 +97,20 @@ enum kNestedSequencesDemo {
kSequenceDemoDig
};
+enum kSequencesLolDemo {
+ kSequenceLolDemoScene1 = 0,
+ kSequenceLolDemoText1,
+ kSequenceLolDemoScene2,
+ kSequenceLolDemoText2,
+ kSequenceLolDemoScene3,
+ kSequenceLolDemoText3,
+ kSequenceLolDemoScene4,
+ kSequenceLolDemoText4,
+ kSequenceLolDemoScene5,
+ kSequenceLolDemoText5,
+ kSequenceLolDemoScene6
+};
+
class WSAMovie_v2;
class KyraEngine_HoF;
class TextDisplayer_HoF;
@@ -242,6 +256,14 @@ protected:
int seq_demoBail(WSAMovie_v2 *wsaObj, int x, int y, int frm);
int seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
void seq_sequenceCommand(int command);
void seq_loadNestedSequence(int wsaNum, int seqNum);
void seq_nestedSequenceFrame(int command, int wsaNum);
@@ -264,7 +286,7 @@ protected:
WSAMovie_v2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos);
void seq_finaleActorScreen();
void seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
- void seq_scrollPage();
+ void seq_scrollPage(int bottom, int top);
void seq_showStarcraftLogo();
void seq_init();
@@ -280,8 +302,7 @@ protected:
static const int8 _dosTrackMap[];
static const int _dosTrackMapSize;
- const AudioDataStruct *_soundData;
-
+ AudioDataStruct _soundData[3];
protected:
// game initialization
void startup();
@@ -886,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 cb3062847e..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:
@@ -633,7 +633,7 @@ protected:
int _soundFilesIntroSize;
const int32 *_cdaTrackTable;
int _cdaTrackTableSize;
- const AudioDataStruct * _soundData;
+ AudioDataStruct _soundData[3];
// positions of the inventory
static const uint16 _itemPosX[];
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index a4e5b58364..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();
@@ -508,7 +508,8 @@ void KyraEngine_MR::snd_playVoiceFile(int file) {
char filename[16];
snprintf(filename, 16, "%.08u", (uint)file);
- _voiceSoundChannel = _soundDigital->playSound(filename, 0xFE, Audio::Mixer::kSpeechSoundType, 255);
+ if (speechEnabled())
+ _voiceSoundChannel = _soundDigital->playSound(filename, 0xFE, Audio::Mixer::kSpeechSoundType, 255);
}
bool KyraEngine_MR::snd_voiceIsPlaying() {
@@ -683,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)
@@ -802,7 +803,12 @@ void KyraEngine_MR::openTalkFile(int file) {
}
_currentTalkFile = file;
- _res->loadPakFile(talkFilename);
+ if (!_res->loadPakFile(talkFilename)) {
+ if (speechEnabled()) {
+ warning("Couldn't load file '%s' falling back to text only mode", talkFilename);
+ _configVoice = 0;
+ }
+ }
}
#pragma mark -
@@ -995,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 85c03dc1bb..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;
@@ -114,7 +112,7 @@ int KyraEngine_v1::init() {
_sound = new SoundTownsPC98_v2(this, _mixer);
} else if (_flags.platform == Common::kPlatformPC98) {
if (_flags.gameID == GI_KYRA1)
- _sound = new SoundTowns/*SoundPC98*/(this, _mixer);
+ _sound = new SoundPC98(this, _mixer);
else
_sound = new SoundTownsPC98_v2(this, _mixer);
} else if (midiDriver == MD_ADLIB) {
@@ -152,6 +150,16 @@ int KyraEngine_v1::init() {
_res = new Resource(this);
assert(_res);
_res->reset();
+
+ if (_flags.isDemo) {
+ // HACK: check whether this is the HOF demo or the LOL demo.
+ // The LOL demo needs to be detected and run as KyraEngine_HoF,
+ // but the static resource loader and the sequence player will
+ // need correct IDs.
+ if (_res->exists("scene1.cps"))
+ _flags.gameID = GI_LOL;
+ }
+
_staticres = new StaticResource(this);
assert(_staticres);
if (!_staticres->init())
@@ -173,6 +181,9 @@ int KyraEngine_v1::init() {
_gameToLoad = -1;
}
+ // Prevent autosave on game startup
+ _lastAutosave = _system->getMillis();
+
return 0;
}
@@ -190,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();
@@ -230,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);
}
@@ -245,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
@@ -262,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 09efc8cc97..f4c2442c0e 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -34,8 +34,8 @@
#include "kyra/script.h"
namespace Common {
-class InSaveFile;
-class OutSaveFile;
+class SeekableReadStream;
+class WriteStream;
} // end of namespace Common
class KyraMetaEngine;
@@ -64,14 +64,15 @@ struct GameFlags {
enum {
GI_KYRA1 = 0,
GI_KYRA2 = 1,
- GI_KYRA3 = 2
+ GI_KYRA3 = 2,
+ GI_LOL = 4
};
struct AudioDataStruct {
const char * const *_fileList;
- const int _fileListLen;
- const void * const _cdaTracks;
- const int _cdaNumTracks;
+ int _fileListLen;
+ const void * _cdaTracks;
+ int _cdaNumTracks;
};
// TODO: this is just the start of makeing the debug output of the kyra engine a bit more useable
@@ -117,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; }
@@ -152,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;
@@ -177,9 +173,6 @@ protected:
virtual int go() = 0;
virtual int init();
- // quit Handling
- bool _quitFlag;
-
// intern
Resource *_res;
Sound *_sound;
@@ -278,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 {
@@ -289,6 +286,8 @@ protected:
bool originalSave; // savegame from original interpreter
bool oldHeader; // old scummvm save header
+
+ Graphics::Surface *thumbnail;
};
enum kReadSaveHeaderError {
@@ -298,10 +297,12 @@ protected:
kRSHEIoError = 3
};
- static kReadSaveHeaderError readSaveHeader(Common::InSaveFile *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::InSaveFile *openSaveForReading(const char *filename, SaveHeader &header);
- Common::OutSaveFile *openSaveForWriting(const char *filename, const char *saveName) const;
+ Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
+ 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
new file mode 100644
index 0000000000..053d8a4de9
--- /dev/null
+++ b/engines/kyra/lol.cpp
@@ -0,0 +1,802 @@
+/* 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/lol.h"
+#include "kyra/screen_lol.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "common/endian.h"
+
+namespace Kyra {
+
+LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) {
+ _screen = 0;
+
+ switch (_flags.lang) {
+ case Common::EN_ANY:
+ case Common::EN_USA:
+ case Common::EN_GRB:
+ _lang = 0;
+ break;
+
+ case Common::FR_FRA:
+ _lang = 1;
+ break;
+
+ case Common::DE_DEU:
+ _lang = 2;
+ break;
+
+ default:
+ warning("unsupported language, switching back to English");
+ _lang = 0;
+ break;
+ }
+
+ _chargenWSA = 0;
+}
+
+LoLEngine::~LoLEngine() {
+ setupPrologueData(false);
+
+ delete _screen;
+ delete _tim;
+
+ for (Common::Array<const TIMOpcode*>::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i)
+ delete *i;
+ _timIntroOpcodes.clear();
+}
+
+Screen *LoLEngine::screen() {
+ return _screen;
+}
+
+int LoLEngine::init() {
+ _screen = new Screen_LoL(this, _system);
+ assert(_screen);
+ _screen->setResolution();
+
+ KyraEngine_v1::init();
+
+ _tim = new TIMInterpreter(this, _screen, _system);
+ assert(_tim);
+
+ _screen->setAnimBlockPtr(10000);
+ _screen->setScreenDim(0);
+
+ if (!_sound->init())
+ error("Couldn't init sound");
+
+ return 0;
+}
+
+int LoLEngine::go() {
+ setupPrologueData(true);
+ showIntro();
+ _sound->playTrack(6);
+ /*int character = */chooseCharacter();
+ _sound->playTrack(1);
+ _screen->fadeToBlack();
+ setupPrologueData(false);
+
+ return 0;
+}
+
+#pragma mark - Input
+
+int LoLEngine::checkInput(Button *buttonList, bool mainLoop) {
+ debugC(9, kDebugLevelMain, "LoLEngine::checkInput(%p, %d)", (const void*)buttonList, mainLoop);
+ updateInput();
+
+ int keys = 0;
+ int8 mouseWheel = 0;
+
+ while (_eventList.size()) {
+ Common::Event event = *_eventList.begin();
+ bool breakLoop = false;
+
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ /*if (event.kbd.keycode >= '1' && event.kbd.keycode <= '9' &&
+ (event.kbd.flags == Common::KBD_CTRL || event.kbd.flags == Common::KBD_ALT) && mainLoop) {
+ const char *saveLoadSlot = getSavegameFilename(9 - (event.kbd.keycode - '0') + 990);
+
+ if (event.kbd.flags == Common::KBD_CTRL) {
+ loadGame(saveLoadSlot);
+ _eventList.clear();
+ breakLoop = true;
+ } else {
+ char savegameName[14];
+ sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
+ saveGame(saveLoadSlot, savegameName);
+ }
+ } else if (event.kbd.flags == Common::KBD_CTRL) {
+ if (event.kbd.keycode == 'd')
+ _debugger->attach();
+ }*/
+ break;
+
+ case Common::EVENT_MOUSEMOVE: {
+ Common::Point pos = getMousePos();
+ _mouseX = pos.x;
+ _mouseY = pos.y;
+ } break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP: {
+ Common::Point pos = getMousePos();
+ _mouseX = pos.x;
+ _mouseY = pos.y;
+ keys = (event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800));
+ breakLoop = true;
+ } break;
+
+ case Common::EVENT_WHEELUP:
+ mouseWheel = -1;
+ break;
+
+ case Common::EVENT_WHEELDOWN:
+ mouseWheel = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ //if (_debugger->isAttached())
+ // _debugger->onFrame();
+
+ if (breakLoop)
+ break;
+
+ _eventList.erase(_eventList.begin());
+ }
+
+ return /*gui_v2()->processButtonList(buttonList, keys | 0x8000, mouseWheel)*/keys;
+}
+
+void LoLEngine::updateInput() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ 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)
+ quitGame();
+ else
+ _eventList.push_back(event);
+ break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ _eventList.push_back(Event(event, true));
+ break;
+
+ case Common::EVENT_MOUSEMOVE:
+ _screen->updateScreen();
+ // fall through
+
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ _eventList.push_back(event);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void LoLEngine::removeInputTop() {
+ if (!_eventList.empty())
+ _eventList.erase(_eventList.begin());
+}
+
+bool LoLEngine::skipFlag() const {
+ for (Common::List<Event>::const_iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip)
+ return true;
+ }
+ return false;
+}
+
+void LoLEngine::resetSkipFlag(bool removeEvent) {
+ for (Common::List<Event>::iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip) {
+ if (removeEvent)
+ _eventList.erase(i);
+ else
+ i->causedSkip = false;
+ return;
+ }
+ }
+}
+
+#pragma mark - Intro
+
+void LoLEngine::setupPrologueData(bool load) {
+ static const char * const fileList[] = {
+ "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 filename[32];
+ for (uint i = 0; i < ARRAYSIZE(fileList); ++i) {
+ filename[0] = '\0';
+
+ if (_flags.isTalkie) {
+ strcpy(filename, _languageExt[_lang]);
+ strcat(filename, "/");
+ }
+
+ strcat(filename, fileList[i]);
+
+ if (load) {
+ if (!_res->loadPakFile(filename))
+ error("Couldn't load file: '%s'", filename);
+ } else {
+ _res->unloadPakFile(filename);
+ }
+ }
+
+ if (load) {
+ _chargenWSA = new WSAMovie_v2(this, _screen);
+ assert(_chargenWSA);
+
+ _charSelection = -1;
+ _charSelectionInfoResult = -1;
+
+ _selectionAnimFrames[0] = _selectionAnimFrames[2] = 0;
+ _selectionAnimFrames[1] = _selectionAnimFrames[3] = 1;
+
+ memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers));
+ memset(_screen->getPalette(1), 0, 768);
+ } else {
+ delete _chargenWSA; _chargenWSA = 0;
+ }
+}
+
+void LoLEngine::showIntro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::showIntro()");
+
+ TIM *intro = _tim->load("LOLINTRO.TIM", &_timIntroOpcodes);
+
+ _screen->loadFont(Screen::FID_8_FNT, "NEW8P.FNT");
+ _screen->loadFont(Screen::FID_INTRO_FNT, "INTRO.FNT");
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _tim->resetFinishedFlag();
+ _tim->setLangData("LOLINTRO.DIP");
+
+ _screen->hideMouse();
+
+ uint32 palNextFadeStep = 0;
+ while (!_tim->finished() && !quit() && !skipFlag()) {
+ updateInput();
+ _tim->exec(intro, false);
+ _screen->checkedPageUpdate(8, 4);
+
+ if (_tim->_palDiff) {
+ if (palNextFadeStep < _system->getMillis()) {
+ _tim->_palDelayAcc += _tim->_palDelayInc;
+ palNextFadeStep = _system->getMillis() + ((_tim->_palDelayAcc >> 8) * _tickLength);
+ _tim->_palDelayAcc &= 0xFF;
+
+ if (!_screen->fadePalStep(_screen->getPalette(0), _tim->_palDiff)) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _tim->_palDiff = 0;
+ }
+ }
+ }
+
+ _system->delayMillis(10);
+ _screen->updateScreen();
+ }
+ _screen->showMouse();
+ _sound->voiceStop();
+
+ // HACK: Remove all input events
+ _eventList.clear();
+
+ _tim->unload(intro);
+ _tim->clearLangData();
+
+ _screen->fadePalette(_screen->getPalette(1), 30, 0);
+}
+
+int LoLEngine::chooseCharacter() {
+ debugC(9, kDebugLevelMain, "LoLEngine::chooseCharacter()");
+
+ _tim->setLangData("LOLINTRO.DIP");
+
+ _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT");
+
+ _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0);
+ _screen->setMouseCursor(0, 0, _screen->getPtrToShape(_screen->getCPagePtr(3), 0));
+
+ while (!_screen->isMouseVisible())
+ _screen->showMouse();
+
+ _screen->loadBitmap("CHAR.CPS", 2, 2, _screen->getPalette(0));
+ _screen->loadBitmap("BACKGRND.CPS", 4, 4, _screen->getPalette(0));
+
+ if (!_chargenWSA->open("CHARGEN.WSA", 1, 0))
+ error("Couldn't load CHARGEN.WSA");
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(2);
+ _chargenWSA->displayFrame(0, 0, 0, 0);
+
+ _screen->setFont(Screen::FID_9_FNT);
+ _screen->_curPage = 2;
+
+ for (int i = 0; i < 4; ++i)
+ _screen->fprintStringIntro(_charPreviews[i].name, _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120);
+
+ for (int i = 0; i < 4; ++i) {
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 48, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[0]);
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 56, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[1]);
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 64, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[2]);
+ }
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(51), 36, 173, 0x98, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(53), 36, 181, 0x98, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(55), 36, 189, 0x98, 0x00, 0x9C, 0x20);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->_curPage = 0;
+
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+
+ bool kingIntro = true;
+ while (!quit()) {
+ if (kingIntro)
+ kingSelectionIntro();
+
+ if (_charSelection < 0)
+ processCharacterSelection();
+
+ if (quit())
+ break;
+
+ if (_charSelection == 100) {
+ kingIntro = true;
+ _charSelection = -1;
+ continue;
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->showMouse();
+
+ if (selectionCharInfo(_charSelection) == -1) {
+ _charSelection = -1;
+ kingIntro = false;
+ } else {
+ break;
+ }
+ }
+
+ if (quit())
+ return -1;
+
+ uint32 waitTime = _system->getMillis() + 420 * _tickLength;
+ while (waitTime > _system->getMillis() && !skipFlag() && !quit()) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ // HACK: Remove all input events
+ _eventList.clear();
+
+ _tim->clearLangData();
+
+ return _charSelection;
+}
+
+void LoLEngine::kingSelectionIntro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionIntro()");
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 38;
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(57), 8, y, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(58), 8, y + 10, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(59), 8, y + 20, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(60), 8, y + 30, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(61), 8, y + 40, 0x32, 0x00, 0x9C, 0x20);
+
+ _sound->voicePlay("KING01");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 4;
+ while (_sound->voiceIsPlaying("KING01") && _charSelection == -1 && !quit() && !skipFlag()) {
+ index = MAX(index, 4);
+
+ _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar1IdxTable[index]*2+0], _selectionPosTable[_selectionChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar2IdxTable[index]*2+0], _selectionPosTable[_selectionChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar3IdxTable[index]*2+0], _selectionPosTable[_selectionChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar4IdxTable[index]*2+0], _selectionPosTable[_selectionChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 7 * _tickLength;
+ while (waitEnd > _system->getMillis() && _charSelection == -1 && !quit() && !skipFlag()) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop("KING01");
+}
+
+void LoLEngine::kingSelectionReminder() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionReminder()");
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 48;
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(62), 8, y, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(63), 8, y + 10, 0x32, 0x00, 0x9C, 0x20);
+
+ _sound->voicePlay("KING02");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 0;
+ 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);
+ _screen->copyRegion(_selectionPosTable[_reminderChar3IdxTable[index]*2+0], _selectionPosTable[_reminderChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar4IdxTable[index]*2+0], _selectionPosTable[_reminderChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 8 * _tickLength;
+ while (waitEnd > _system->getMillis() && !quit()) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ _sound->voiceStop("KING02");
+}
+
+void LoLEngine::kingSelectionOutro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionOutro()");
+
+ _sound->voicePlay("KING03");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 0;
+ 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() && !quit() && !skipFlag()) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop("KING03");
+}
+
+void LoLEngine::processCharacterSelection() {
+ debugC(9, kDebugLevelMain, "LoLEngine::processCharacterSelection()");
+
+ _charSelection = -1;
+ while (!quit() && _charSelection == -1) {
+ uint32 nextKingMessage = _system->getMillis() + 900 * _tickLength;
+
+ while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !quit()) {
+ updateSelectionAnims();
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ if (_charSelection == -1)
+ kingSelectionReminder();
+ }
+}
+
+void LoLEngine::updateSelectionAnims() {
+ debugC(9, kDebugLevelMain, "LoLEngine::updateSelectionAnims()");
+
+ for (int i = 0; i < 4; ++i) {
+ if (_system->getMillis() < _selectionAnimTimers[i])
+ continue;
+
+ const int index = _selectionAnimIndexTable[_selectionAnimFrames[i] + i * 2];
+ _screen->copyRegion(_selectionPosTable[index*2+0], _selectionPosTable[index*2+1], _charPreviews[i].x, _charPreviews[i].y, 32, 32, 4, 0);
+
+ int delayTime = 0;
+ if (_selectionAnimFrames[i] == 1)
+ delayTime = _rnd.getRandomNumberRng(0, 31) + 80;
+ else
+ delayTime = _rnd.getRandomNumberRng(0, 3) + 10;
+
+ _selectionAnimTimers[i] = _system->getMillis() + delayTime * _tickLength;
+ _selectionAnimFrames[i] = (_selectionAnimFrames[i] + 1) % 2;
+ }
+
+ _screen->updateScreen();
+}
+
+int LoLEngine::selectionCharInfo(int character) {
+ debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfo(%d)", character);
+ if (character < 0)
+ return -1;
+
+ char filename[16];
+ char vocFilename[6];
+ strcpy(vocFilename, "000X0");
+
+ switch (character) {
+ case 0:
+ strcpy(filename, "FACE09.SHP");
+ vocFilename[3] = 'A';
+ break;
+
+ case 1:
+ strcpy(filename, "FACE01.SHP");
+ vocFilename[3] = 'M';
+ break;
+
+ case 2:
+ strcpy(filename, "FACE08.SHP");
+ vocFilename[3] = 'K';
+ break;
+
+ case 3:
+ strcpy(filename, "FACE05.SHP");
+ vocFilename[3] = 'C';
+ break;
+
+ default:
+ break;
+ };
+
+ _screen->loadBitmap(filename, 9, 9, 0);
+ _screen->copyRegion(0, 122, 0, 122, 320, 78, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(_charPreviews[character].x - 3, _charPreviews[character].y - 3, 8, 127, 38, 38, 2, 0);
+
+ static const uint8 charSelectInfoIdx[] = { 0x1D, 0x22, 0x27, 0x2C };
+ const int idx = charSelectInfoIdx[character];
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+0), 50, 127, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+1), 50, 137, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+2), 50, 147, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+3), 50, 157, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+4), 50, 167, 0x53, 0x00, 0xCF, 0x20);
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(69), 100, 168, 0x32, 0x00, 0xCF, 0x20);
+
+ selectionCharInfoIntro(vocFilename);
+ if (_charSelectionInfoResult == -1) {
+ while (_charSelectionInfoResult == -1) {
+ _charSelectionInfoResult = selectionCharAccept();
+ _system->delayMillis(10);
+ }
+ }
+
+ if (_charSelectionInfoResult != 1) {
+ _charSelectionInfoResult = -1;
+ _screen->copyRegion(0, 122, 0, 122, 320, 78, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ return -1;
+ }
+
+ _screen->copyRegion(48, 127, 48, 127, 272, 60, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->hideMouse();
+ _screen->copyRegion(48, 127, 48, 160, 272, 35, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(64), 3, 28, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(65), 3, 38, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(66), 3, 48, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(67), 3, 58, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(68), 3, 68, 0x32, 0x00, 0x9C, 0x20);
+
+ resetSkipFlag();
+ kingSelectionOutro();
+ return character;
+}
+
+void LoLEngine::selectionCharInfoIntro(char *file) {
+ debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfoIntro(%p)", (const void *)file);
+ int index = 0;
+ file[4] = '0';
+
+ while (_charSelectionInfoResult == -1 && !quit()) {
+ if (!_sound->voicePlay(file))
+ break;
+
+ int i = 0;
+ while (_sound->voiceIsPlaying(file) && _charSelectionInfoResult == -1 && !quit()) {
+ _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), _charInfoFrameTable[i]), 11, 130, 0, 0);
+ _screen->updateScreen();
+
+ uint32 nextFrame = _system->getMillis() + 8 * _tickLength;
+ while (nextFrame > _system->getMillis() && _charSelectionInfoResult == -1) {
+ _charSelectionInfoResult = selectionCharAccept();
+ _system->delayMillis(10);
+ }
+
+ i = (i + 1) % 32;
+ }
+
+ _sound->voiceStop(file);
+ file[4] = ++index + '0';
+ }
+
+ _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), 0), 11, 130, 0, 0);
+ _screen->updateScreen();
+}
+
+int LoLEngine::getCharSelection() {
+ int inputFlag = checkInput() & 0xCF;
+ removeInputTop();
+
+ if (inputFlag == 200) {
+ for (int i = 0; i < 4; ++i) {
+ if (_charPreviews[i].x <= _mouseX && _mouseX <= _charPreviews[i].x + 31 &&
+ _charPreviews[i].y <= _mouseY && _mouseY <= _charPreviews[i].y + 31)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int LoLEngine::selectionCharAccept() {
+ int inputFlag = checkInput() & 0xCF;
+ removeInputTop();
+
+ if (inputFlag == 200) {
+ if (88 <= _mouseX && _mouseX <= 128 && 180 <= _mouseY && _mouseY <= 194)
+ return 1;
+ if (196 <= _mouseX && _mouseX <= 236 && 180 <= _mouseY && _mouseY <= 194)
+ return 0;
+ }
+
+ return -1;
+}
+
+#pragma mark - Opcodes
+
+typedef Common::Functor2Mem<const TIM *, const uint16 *, int, LoLEngine> TIMOpcodeLoL;
+#define SetTimOpcodeTable(x) timTable = &x;
+#define OpcodeTim(x) timTable->push_back(new TIMOpcodeLoL(this, &LoLEngine::x))
+#define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0))
+
+void LoLEngine::setupOpcodeTable() {
+ Common::Array<const TIMOpcode*> *timTable = 0;
+
+ SetTimOpcodeTable(_timIntroOpcodes);
+
+ // 0x00
+ OpcodeTim(tlol_setupPaletteFade);
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_loadPalette);
+ OpcodeTim(tlol_setupPaletteFadeEx);
+
+ // 0x04
+ OpcodeTim(tlol_processWsaFrame);
+ OpcodeTim(tlol_displayText);
+ OpcodeTimUnImpl();
+ OpcodeTimUnImpl();
+}
+
+#pragma mark -
+
+int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::t2_playSoundEffect(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadPalette(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1)));
+ _res->loadFileToBuf(palFile, _screen->getPalette(0), 768);
+ return 1;
+}
+
+int LoLEngine::tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setupPaletteFadeEx(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ memcpy(_screen->getPalette(0), _screen->getPalette(1), 768);
+
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_processWsaFrame(%p, %p) (%d, %d, %d, %d, %d)",
+ (const void*)tim, (const void*)param, param[0], param[1], param[2], param[3], param[4]);
+ TIMInterpreter::Animation *anim = (TIMInterpreter::Animation *)tim->wsa[param[0]].anim;
+ const int frame = param[1];
+ const int x2 = param[2];
+ const int y2 = param[3];
+ const int factor = MAX<int>(0, (int16)param[4]);
+
+ const int x1 = anim->x;
+ const int y1 = anim->y;
+
+ int w1 = anim->wsa->width();
+ int h1 = anim->wsa->height();
+ int w2 = (w1 * factor) / 100;
+ int h2 = (h1 * factor) / 100;
+
+ anim->wsa->setDrawPage(2);
+ anim->wsa->setX(x1);
+ anim->wsa->setY(y1);
+ anim->wsa->displayFrame(frame, anim->wsaCopyParams & 0xF0FF, 0, 0);
+ _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, 8, 0);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+
+ return 1;
+}
+
+int LoLEngine::tlol_displayText(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_displayText(%p, %p) (%d, %d)", (const void*)tim, (const void*)param, param[0], (int16)param[1]);
+ _tim->displayText(param[0], param[1]);
+ return 1;
+}
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
new file mode 100644
index 0000000000..2ae4d71580
--- /dev/null
+++ b/engines/kyra/lol.h
@@ -0,0 +1,158 @@
+/* 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_LOL_H
+#define KYRA_LOL_H
+
+#include "kyra/kyra_v1.h"
+#include "kyra/script_tim.h"
+
+#include "common/list.h"
+
+namespace Kyra {
+
+class Screen_LoL;
+class WSAMovie_v2;
+struct Button;
+
+class LoLEngine : public KyraEngine_v1 {
+public:
+ LoLEngine(OSystem *system, const GameFlags &flags);
+ ~LoLEngine();
+
+ Screen *screen();
+private:
+ Screen_LoL *_screen;
+ TIMInterpreter *_tim;
+
+ int init();
+ int go();
+
+ // input
+ void updateInput();
+ int checkInput(Button *buttonList = 0, bool mainLoop = false);
+ void removeInputTop();
+
+ int _mouseX, _mouseY;
+
+ struct Event {
+ Common::Event event;
+ bool causedSkip;
+
+ Event() : event(), causedSkip(false) {}
+ Event(Common::Event e) : event(e), causedSkip(false) {}
+ Event(Common::Event e, bool skip) : event(e), causedSkip(skip) {}
+
+ operator Common::Event() const { return event; }
+ };
+ Common::List<Event> _eventList;
+
+ virtual bool skipFlag() const;
+ virtual void resetSkipFlag(bool removeEvent = true);
+
+ // intro
+ void setupPrologueData(bool load);
+
+ void showIntro();
+
+ struct CharacterPrev {
+ const char *name;
+ int x, y;
+ int attrib[3];
+ };
+
+ static const CharacterPrev _charPreviews[];
+
+ WSAMovie_v2 *_chargenWSA;
+ static const uint8 _chargenFrameTable[];
+ int chooseCharacter();
+
+ void kingSelectionIntro();
+ void kingSelectionReminder();
+ void kingSelectionOutro();
+ void processCharacterSelection();
+ void updateSelectionAnims();
+ int selectionCharInfo(int character);
+ void selectionCharInfoIntro(char *file);
+
+ int getCharSelection();
+ int selectionCharAccept();
+
+ int _charSelection;
+ int _charSelectionInfoResult;
+
+ uint32 _selectionAnimTimers[4];
+ uint8 _selectionAnimFrames[4];
+ static const uint8 _selectionAnimIndexTable[];
+
+ static const uint16 _selectionPosTable[];
+
+ static const uint8 _selectionChar1IdxTable[];
+ static const uint8 _selectionChar2IdxTable[];
+ static const uint8 _selectionChar3IdxTable[];
+ static const uint8 _selectionChar4IdxTable[];
+
+ static const uint8 _reminderChar1IdxTable[];
+ static const uint8 _reminderChar2IdxTable[];
+ static const uint8 _reminderChar3IdxTable[];
+ static const uint8 _reminderChar4IdxTable[];
+
+ static const uint8 _charInfoFrameTable[];
+
+ // timer
+ void setupTimers() {}
+
+ // sound
+ void snd_playVoiceFile(int) { /* XXX */ }
+
+ // opcode
+ void setupOpcodeTable();
+
+ Common::Array<const TIMOpcode*> _timIntroOpcodes;
+ int tlol_setupPaletteFade(const TIM *tim, const uint16 *param);
+ int tlol_loadPalette(const TIM *tim, const uint16 *param);
+ int tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param);
+ int tlol_processWsaFrame(const TIM *tim, const uint16 *param);
+ int tlol_displayText(const TIM *tim, const uint16 *param);
+
+ // translation
+ int _lang;
+
+ static const char * const _languageExt[];
+
+ // unneeded
+ void setWalkspeed(uint8) {}
+ 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
+
+#endif
+
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index ebb63b4b4e..b38661ada5 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -21,7 +21,9 @@ MODULE_OBJS := \
kyra_v2.o \
kyra_hof.o \
kyra_mr.o \
+ lol.o \
resource.o \
+ resource_intern.o \
saveload.o \
saveload_lok.o \
saveload_hof.o \
@@ -33,6 +35,7 @@ MODULE_OBJS := \
scene_mr.o \
screen.o \
screen_lok.o \
+ screen_lol.o \
screen_v2.o \
screen_hof.o \
screen_mr.o \
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index afd7eacfda..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,44 +72,38 @@ 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");
}
return true;
} else if (_vm->game() == GI_KYRA3) {
- if (_vm->gameFlags().useInstallerPackage)
- loadPakFile("WESTWOOD.001");
+ if (_vm->gameFlags().useInstallerPackage) {
+ if (!loadPakFile("WESTWOOD.001"))
+ 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'");
- loadFileList("FILEDATA.FDT");
+ return true;
+ } else if (_vm->game() == GI_LOL) {
+ if (_vm->gameFlags().useInstallerPackage)
+ _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) {
@@ -112,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();
@@ -141,107 +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;
- }
-
- 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()) {
- // A new file entry, so we just insert it into the file map.
- _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.
- }
+ _archiveFiles->add(filename, archive, 0);
- 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;
}
@@ -259,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) {
@@ -304,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);
@@ -314,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) {
@@ -337,1152 +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 (Common::File::exists(file)) {
- 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 if ((compEntry = _compFiles.find(file)) != _compFiles.end()) {
- return new Common::MemoryReadStream(compEntry->_value.data, compEntry->_value.size, false);
- } else {
- if (!isAccessable(file))
- return 0;
-
- ResFileMap::const_iterator iter = _map.find(file);
- if (iter == _map.end())
- return 0;
-
- if (!iter->_value.parent.empty()) {
- 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);
- } else {
- error("Couldn't open file '%s'", file.c_str());
- }
- }
-
- 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 (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();
- }
- } else 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();
- }
- }
+ return _files.openFile(file);
}
-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;
+Common::ArchivePtr Resource::loadArchive(const Common::String &file) {
+ ArchiveMap::iterator cachedArchive = _archiveCache.find(file);
+ if (cachedArchive != _archiveCache.end())
+ return cachedArchive->_value;
- 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()));
-}
-
-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;
-
- // 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);
+ stream->seek(0, SEEK_SET);
}
}
}
- 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 &para);
-
- 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];
- const 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((void*) 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 &para) {
- 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);
+ delete stream;
- return newIndex;
-}
+ if (!archive)
+ return Common::ArchivePtr();
-class CompLoaderInsHof : public CompArchiveLoader {
-public:
- bool checkForFiles() const;
- bool loadFile(CompFileMap &loadTo) const;
-
-private:
- struct Archive {
- Common::String filename;
- uint32 firstFile;
- uint32 startOffset;
- uint32 lastFile;
- uint32 endOffset;
- uint32 totalSize;
- };
-};
-
-bool CompLoaderInsHof::checkForFiles() const {
- return (Common::File::exists("WESTWOOD.001") && Common::File::exists("WESTWOOD.002"));
+ _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, "%03d", 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 -= 6;
- pos += 6;
- tmpFile.seek(6, 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;
- 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, "%03d", 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;
- exp.process(outbuffer, inbuffer, outsize, insize);
- 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, "%03d", 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) {
- if (hdr[8] != 8)
- error("compression type not implemented");
- 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;
- exp.process(outbuffer, inbuffer, outsize, insize);
- 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 -
@@ -1491,16 +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()));
-}
-
-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 &para);
+
+ 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 &para) {
+ 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 22f934ba69..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::InSaveFile *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;
@@ -95,6 +97,9 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::InSave
if (header.version <= 8) {
char buffer[31];
in->read(buffer, 31);
+ // WORKAROUND: Old savegames could contain a missing termination 0 at the
+ // end so we manually add it.
+ buffer[30] = 0;
header.description = buffer;
} else {
header.description = "";
@@ -105,17 +110,30 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::InSave
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);
}
-Common::InSaveFile *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
+Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForReading('%s', -)", filename);
- Common::InSaveFile *in = 0;
+ Common::SeekableReadStream *in = 0;
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.");
@@ -159,12 +177,12 @@ Common::InSaveFile *KyraEngine_v1::openSaveForReading(const char *filename, Save
return in;
}
-Common::OutSaveFile *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::OutSaveFile *out = 0;
+ Common::WriteStream *out = 0;
if (!(out = _saveFileMan->openForSaving(filename))) {
warning("Can't create file '%s', game not saved", filename);
return 0;
@@ -188,20 +206,27 @@ Common::OutSaveFile *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) {
@@ -209,7 +234,7 @@ bool KyraEngine_v1::saveFileLoadable(int slot) {
return false;
SaveHeader header;
- Common::InSaveFile *in = openSaveForReading(getSavegameFilename(slot), header);
+ Common::SeekableReadStream *in = openSaveForReading(getSavegameFilename(slot), header);
if (in) {
delete in;
@@ -219,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 e4a3a5c54e..ad4ce63b6c 100644
--- a/engines/kyra/scene_mr.cpp
+++ b/engines/kyra/scene_mr.cpp
@@ -378,10 +378,11 @@ void KyraEngine_MR::loadSceneMsc() {
_screen->loadBitmap(filename, 5, 5, 0, true);
// HACK
- uint8 data[320*200];
+ uint8 *data = new uint8[320*200];
_screen->copyRegionToBuffer(5, 0, 0, 320, 200, data);
_screen->clearPage(5);
_screen->copyBlockToPage(5, 0, _maskPageMinY, 320, height, data);
+ delete[] data;
musicUpdate(0);
}
@@ -653,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 74f7bc6de9..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();
}
@@ -413,7 +413,9 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u
void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) {
debugC(9, kDebugLevelScreen, "Screen::getFadeParams(%p, %d, %p, %p)", (const void *)palette, delay, (const void *)&delayInc, (const void *)&diff);
uint8 maxDiff = 0;
- for (int i = 0; i < 768; ++i) {
+
+ const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256) * 3;
+ for (int i = 0; i < colors; ++i) {
diff = ABS(palette[i] - _screenPalette[i]);
maxDiff = MAX<uint8>(maxDiff, diff);
}
@@ -438,7 +440,8 @@ int Screen::fadePalStep(const uint8 *palette, int diff) {
memcpy(fadePal, _screenPalette, 768);
bool needRefresh = false;
- for (int i = 0; i < 768; ++i) {
+ const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256) * 3;
+ for (int i = 0; i < colors; ++i) {
int c1 = palette[i];
int c2 = fadePal[i];
if (c1 != c2) {
@@ -473,10 +476,29 @@ 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);
- int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256);
+ const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256);
if (palData != _screenPalette)
memcpy(_screenPalette, palData, colors*3);
@@ -551,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;
@@ -2736,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/screen_lol.cpp b/engines/kyra/screen_lol.cpp
new file mode 100644
index 0000000000..c6b47a9ca9
--- /dev/null
+++ b/engines/kyra/screen_lol.cpp
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "kyra/screen_lol.h"
+#include "kyra/lol.h"
+
+namespace Kyra {
+
+Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) {
+}
+
+void Screen_LoL::setScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim);
+ assert(dim < _screenDimTableCount);
+ _curDim = &_screenDimTable[dim];
+}
+
+const ScreenDim *Screen_LoL::getScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::getScreenDim(%d)", dim);
+ assert(dim < _screenDimTableCount);
+ return &_screenDimTable[dim];
+}
+
+void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::fprintStringIntro('%s', %d, %d, %d, %d, %d, %d, ...)", format, x, y, c1, c2, c3, flags);
+ char buffer[400];
+
+ va_list args;
+ va_start(args, flags);
+ vsprintf(buffer, format, args);
+ va_end(args);
+
+ if ((flags & 0x0F00) == 0x100)
+ x -= getTextWidth(buffer) >> 1;
+ if ((flags & 0x0F00) == 0x200)
+ x -= getTextWidth(buffer);
+
+ if ((flags & 0x00F0) == 0x20) {
+ printText(buffer, x-1, y, c3, c2);
+ printText(buffer, x, y+1, c3, c2);
+ }
+
+ printText(buffer, x, y, c1, c2);
+}
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
new file mode 100644
index 0000000000..38df3ca897
--- /dev/null
+++ b/engines/kyra/screen_lol.h
@@ -0,0 +1,53 @@
+/* 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_SCREEN_LOL_H
+#define KYRA_SCREEN_LOL_H
+
+#include "kyra/screen_v2.h"
+
+namespace Kyra {
+
+class LoLEngine;
+
+class Screen_LoL : public Screen_v2 {
+public:
+ Screen_LoL(LoLEngine *vm, OSystem *system);
+
+ void setScreenDim(int dim);
+ const ScreenDim *getScreenDim(int dim);
+
+ void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...);
+private:
+ LoLEngine *_vm;
+
+ static const ScreenDim _screenDimTable[];
+ static const int _screenDimTableCount;
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index e5d851aeab..c6ea6a93e8 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -485,5 +485,27 @@ bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, i
return (w1 == -1) ? false : true;
}
+void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::checkedPageUpdate(%d, %d)", srcPage, dstPage);
+
+ const uint32 *src = (const uint32 *)getPagePtr(srcPage);
+ uint32 *dst = (uint32 *)getPagePtr(dstPage);
+ uint32 *page0 = (uint32 *)getPagePtr(0);
+
+ bool updated = false;
+
+ for (int y = 0; y < 200; ++y) {
+ for (int x = 0; x < 80; ++x, ++src, ++dst, ++page0) {
+ if (*src != *dst) {
+ updated = true;
+ *dst = *page0 = *src;
+ }
+ }
+ }
+
+ if (updated)
+ addDirtyRect(0, 0, 320, 200);
+}
+
} // end of namespace Kyra
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index 3283526ee3..7bbdc4b6c3 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -40,6 +40,8 @@ public:
void copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src,
int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2);
+ void checkedPageUpdate(int srcPage, int dstPage);
+
// palette handling
uint8 *generateOverlay(const uint8 *palette, uint8 *buffer, int color, uint16 factor);
void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay);
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/script_tim.cpp b/engines/kyra/script_tim.cpp
index 4b82232049..9b215b2c03 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -26,12 +26,14 @@
#include "kyra/script_tim.h"
#include "kyra/script.h"
#include "kyra/resource.h"
+#include "kyra/sound.h"
+#include "kyra/wsamovie.h"
#include "common/endian.h"
namespace Kyra {
-TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) {
+TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system) : _vm(vm), _screen(screen), _system(system), _currentTim(0) {
#define COMMAND(x) { &TIMInterpreter::x, #x }
#define COMMAND_UNIMPL() { 0, 0 }
#define cmd_return(n) cmd_return_##n
@@ -39,32 +41,32 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s
// 0x00
COMMAND(cmd_initFunc0),
COMMAND(cmd_stopCurFunc),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_initWSA),
+ COMMAND(cmd_uninitWSA),
// 0x04
COMMAND(cmd_initFunc),
COMMAND(cmd_stopFunc),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_wsaDisplayFrame),
COMMAND_UNIMPL(),
// 0x08
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_loadVocFile),
+ COMMAND(cmd_unloadVocFile),
+ COMMAND(cmd_playVocFile),
COMMAND_UNIMPL(),
// 0x0C
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_loadSoundFile),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_playMusicTrack),
COMMAND_UNIMPL(),
// 0x10
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
COMMAND_UNIMPL(),
COMMAND_UNIMPL(),
// 0x14
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_setLoopIp),
+ COMMAND(cmd_continueLoop),
+ COMMAND(cmd_resetLoopIp),
COMMAND(cmd_resetAllRuntimes),
// 0x18
COMMAND(cmd_return(1)),
@@ -80,6 +82,19 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s
_commands = commandProcs;
_commandsSize = ARRAYSIZE(commandProcs);
+
+ memset(&_animations, 0, sizeof(_animations));
+ _langData = 0;
+ _textDisplayed = false;
+ _textAreaBuffer = new uint8[320*40];
+ assert(_textAreaBuffer);
+
+ _palDelayInc = _palDiff = _palDelayAcc = 0;
+}
+
+TIMInterpreter::~TIMInterpreter() {
+ delete[] _langData;
+ delete[] _textAreaBuffer;
}
TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes) {
@@ -139,6 +154,11 @@ void TIMInterpreter::unload(TIM *&tim) const {
tim = 0;
}
+void TIMInterpreter::setLangData(const char *filename) {
+ delete[] _langData;
+ _langData = _vm->resource()->fileData(filename, 0);
+}
+
void TIMInterpreter::exec(TIM *tim, bool loop) {
if (!tim)
return;
@@ -175,6 +195,10 @@ void TIMInterpreter::exec(TIM *tim, bool loop) {
_currentTim->procFunc = _currentFunc;
break;
+ case 22:
+ cur.loopIp = 0;
+ break;
+
default:
break;
}
@@ -201,6 +225,205 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) {
}
}
+void TIMInterpreter::displayText(uint16 textId, int16 flags) {
+ char *text = getTableEntry(textId);
+
+ if (_textDisplayed) {
+ _screen->copyBlockToPage(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = false;
+ }
+
+ if (!text)
+ return;
+ if (!text[0])
+ return;
+
+ char filename[16];
+ memset(filename, 0, sizeof(filename));
+
+ if (text[0] == '$') {
+ const char *end = strchr(text+1, '$');
+ if (end)
+ memcpy(filename, text+1, end-1-text);
+ }
+
+ if (filename[0])
+ _vm->sound()->voicePlay(filename);
+
+ if (text[0] == '$')
+ text = strchr(text + 1, '$') + 1;
+
+ setupTextPalette((flags < 0) ? 1 : flags, 0);
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(Screen::FID_8_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = -2;
+ }
+
+ _screen->_charOffset = -4;
+ _screen->copyRegionToBuffer(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = true;
+
+ char backupChar = 0;
+ char *str = text;
+ int heightAdd = 0;
+
+ while (str[0]) {
+ char *nextLine = strchr(str, '\r');
+
+ backupChar = 0;
+ if (nextLine) {
+ backupChar = nextLine[0];
+ nextLine[0] = '\0';
+ }
+
+ int width = _screen->getTextWidth(str);
+
+ if (flags >= 0)
+ _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, 0xF0, 0x00);
+ else
+ _screen->printText(str, (320 - width) >> 1, 188, 0xF0, 0x00);
+
+ heightAdd += _screen->getFontHeight();
+ str += strlen(str);
+
+ if (backupChar) {
+ nextLine[0] = backupChar;
+ ++str;
+ }
+ }
+
+ _screen->_charOffset = 0;
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(Screen::FID_INTRO_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = 0;
+ }
+}
+
+void TIMInterpreter::setupTextPalette(uint index, int fadePalette) {
+ static const uint16 palTable[] = {
+ 0x00, 0x00, 0x00,
+ 0x64, 0x64, 0x64,
+ 0x61, 0x51, 0x30,
+ 0x29, 0x48, 0x64,
+ 0x00, 0x4B, 0x3B,
+ 0x64, 0x1E, 0x1E,
+ };
+
+ for (int i = 0; i < 15; ++i) {
+ uint8 *palette = _screen->getPalette(0) + (240 + i) * 3;
+
+ uint8 c1 = (((15 - i) << 2) * palTable[index*3+0]) / 100;
+ uint8 c2 = (((15 - i) << 2) * palTable[index*3+1]) / 100;
+ uint8 c3 = (((15 - i) << 2) * palTable[index*3+2]) / 100;
+
+ palette[0] = c1;
+ palette[1] = c2;
+ palette[2] = c3;
+ }
+
+ if (!fadePalette && !_palDiff) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->getFadeParams(_screen->getPalette(0), fadePalette, _palDelayInc, _palDiff);
+ _palDelayAcc = 0;
+ }
+}
+
+TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags) {
+ Animation *anim = &_animations[index];
+ anim->x = x;
+ anim->y = y;
+ anim->wsaCopyParams = wsaFlags;
+
+ uint16 wsaOpenFlags = ((wsaFlags & 0x10) != 0) ? 2 : 0;
+
+ char file[32];
+ snprintf(file, 32, "%s.WSA", filename);
+
+ if (_vm->resource()->exists(file)) {
+ anim->wsa = new WSAMovie_v2(_vm, _screen);
+ assert(anim->wsa);
+
+ anim->wsa->open(file, wsaOpenFlags, (index == 1) ? _screen->getPalette(0) : 0);
+ }
+
+ if (anim->wsa && anim->wsa->opened()) {
+ if (x == -1)
+ anim->x = x = 0;
+ if (y == -1)
+ anim->y = y = 0;
+
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(8);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 4) {
+ snprintf(file, 32, "%s.CPS", filename);
+
+ if (_vm->resource()->exists(file)) {
+ _screen->loadBitmap(file, 3, 3, _screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ anim->wsa->setX(x);
+ anim->wsa->setY(y);
+ anim->wsa->setDrawPage(0);
+ anim->wsa->displayFrame(0, 0, 0, 0);
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ } else {
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(8);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ snprintf(file, 32, "%s.CPS", filename);
+
+ if (_vm->resource()->exists(file)) {
+ _screen->loadBitmap(file, 3, 3, _screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ }
+
+ return anim;
+}
+
+char *TIMInterpreter::getTableEntry(uint idx) {
+ if (!_langData)
+ return 0;
+ else
+ return (char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
+const char *TIMInterpreter::getCTableEntry(uint idx) const {
+ if (!_langData)
+ return 0;
+ else
+ return (const char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
if (cmd < 0 || cmd >= _commandsSize) {
warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
@@ -212,11 +435,14 @@ int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
return 0;
}
- debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void*)param);
+ debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void* )param);
return (this->*_commands[cmd].proc)(param);
}
int TIMInterpreter::cmd_initFunc0(const uint16 *param) {
+ for (int i = 0; i < TIM::kWSASlots; ++i)
+ memset(&_currentTim->wsa[i], 0, sizeof(TIM::WSASlot));
+
_currentTim->func[0].ip = _currentTim->func[0].avtl;
_currentTim->func[0].lastTime = _system->getMillis();
return 1;
@@ -230,6 +456,46 @@ int TIMInterpreter::cmd_stopCurFunc(const uint16 *param) {
return -2;
}
+int TIMInterpreter::cmd_initWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ slot.x = int16(param[2]);
+ slot.y = int16(param[3]);
+ slot.offscreen = param[4];
+ slot.wsaFlags = param[5];
+ const char *filename = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[1]<<1)));
+
+ slot.anim = initAnimStruct(index, filename, slot.x, slot.y, 10, slot.offscreen, slot.wsaFlags);
+ return 1;
+}
+
+int TIMInterpreter::cmd_uninitWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ if (!slot.anim)
+ return 0;
+
+ Animation &anim = _animations[index];
+
+ if (slot.offscreen) {
+ delete anim.wsa;
+ anim.wsa = 0;
+ slot.anim = 0;
+ } else {
+ //XXX
+
+ delete anim.wsa;
+ memset(&anim, 0, sizeof(Animation));
+ memset(&slot, 0, sizeof(TIM::WSASlot));
+ }
+
+ return 1;
+}
+
int TIMInterpreter::cmd_initFunc(const uint16 *param) {
uint16 func = *param;
assert(func < TIM::kCountFuncs);
@@ -247,6 +513,89 @@ int TIMInterpreter::cmd_stopFunc(const uint16 *param) {
return 1;
}
+int TIMInterpreter::cmd_wsaDisplayFrame(const uint16 *param) {
+ Animation &anim = _animations[param[0]];
+ const int frame = param[1];
+
+ anim.wsa->setX(anim.x);
+ anim.wsa->setY(anim.y);
+ anim.wsa->setDrawPage((anim.wsaCopyParams & 0x4000) != 0 ? 2 : 8);
+ anim.wsa->displayFrame(frame, anim.wsaCopyParams & 0xF0FF, 0, 0);
+ return 1;
+}
+
+int TIMInterpreter::cmd_displayText(const uint16 *param) {
+ displayText(param[0], param[1]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadVocFile(const uint16 *param) {
+ const int stringId = param[0];
+ const int index = param[1];
+
+ _vocFiles[index] = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (stringId << 1)));
+ for (int i = 0; i < 4; ++i)
+ _vocFiles[index].deleteLastChar();
+ return 1;
+}
+
+int TIMInterpreter::cmd_unloadVocFile(const uint16 *param) {
+ const int index = param[0];
+ _vocFiles[index].clear();
+ return 1;
+}
+
+int TIMInterpreter::cmd_playVocFile(const uint16 *param) {
+ const int index = param[0];
+ const int volume = (param[1] * 255) / 100;
+
+ if (index < ARRAYSIZE(_vocFiles) && !_vocFiles[index].empty())
+ _vm->sound()->voicePlay(_vocFiles[index].c_str()/*, volume*/, true);
+ else
+ _vm->snd_playSoundEffect(index, volume);
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadSoundFile(const uint16 *param) {
+ const char *file = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[0]<<1)));
+ _vm->sound()->loadSoundFile(file);
+ return 1;
+}
+
+int TIMInterpreter::cmd_playMusicTrack(const uint16 *param) {
+ _vm->sound()->playTrack(param[0]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_setLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip;
+ return 1;
+}
+
+int TIMInterpreter::cmd_continueLoop(const uint16 *param) {
+ TIM::Function &func = _currentTim->func[_currentFunc];
+
+ if (!func.loopIp)
+ return -2;
+
+ func.ip = func.loopIp;
+
+ uint16 factor = param[0];
+ if (factor) {
+ const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000);
+ uint32 waitTime = (random * factor) / 0x8000;
+ func.nextTime += waitTime * _vm->tickLength();
+ }
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_resetLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = 0;
+ return 1;
+}
+
int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) {
for (int i = 0; i < TIM::kCountFuncs; ++i) {
if (_currentTim->func[i].ip)
@@ -256,17 +605,23 @@ int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) {
}
int TIMInterpreter::cmd_execOpcode(const uint16 *param) {
+ const uint16 opcode = *param++;
+
if (!_currentTim->opcodes) {
- warning("Trying to execute TIM opcode without opcode list");
+ warning("Trying to execute TIM opcode %d without opcode list (file '%s')", opcode, _currentTim->filename);
return 0;
}
- uint16 opcode = *param++;
if (opcode > _currentTim->opcodes->size()) {
warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
return 0;
}
+ if (!(*_currentTim->opcodes)[opcode]->isValid()) {
+ warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
+ return 0;
+ }
+
return (*(*_currentTim->opcodes)[opcode])(_currentTim, param);
}
diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h
index 39a1d90a44..68ef23fd6c 100644
--- a/engines/kyra/script_tim.h
+++ b/engines/kyra/script_tim.h
@@ -30,9 +30,12 @@
#include "common/array.h"
#include "common/func.h"
+#include "common/str.h"
namespace Kyra {
+class WSAMovie_v2;
+class Screen_v2;
struct TIM;
typedef Common::Functor2<const TIM*, const uint16*, int> TIMOpcode;
@@ -52,9 +55,23 @@ struct TIM {
uint32 lastTime;
uint32 nextTime;
+ const uint16 *loopIp;
+
const uint16 *avtl;
} func[kCountFuncs];
+ enum {
+ kWSASlots = 10
+ };
+
+ struct WSASlot {
+ void *anim;
+
+ int16 x, y;
+ uint16 wsaFlags;
+ uint16 offscreen;
+ } wsa[kWSASlots];
+
uint16 *avtl;
uint8 *text;
@@ -63,10 +80,22 @@ struct TIM {
class TIMInterpreter {
public:
- TIMInterpreter(KyraEngine_v1 *vm, OSystem *system);
+ struct Animation {
+ WSAMovie_v2 *wsa;
+ int16 x, y;
+ uint16 wsaCopyParams;
+ };
+
+ TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system);
+ ~TIMInterpreter();
TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes);
void unload(TIM *&tim) const;
+
+ void setLangData(const char *filename);
+ void clearLangData() { delete[] _langData; _langData = 0; }
+
+ const char *getCTableEntry(uint idx) const;
void resetFinishedFlag() { _finished = false; }
bool finished() const { return _finished; }
@@ -74,10 +103,15 @@ public:
void exec(TIM *tim, bool loop);
void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); }
- void play(const char *filename);
void refreshTimersAfterPause(uint32 elapsedTime);
+
+ void displayText(uint16 textId, int16 flags);
+ void setupTextPalette(uint index, int fadePalette);
+
+ int _palDelayInc, _palDiff, _palDelayAcc;
private:
KyraEngine_v1 *_vm;
+ Screen_v2 *_screen;
OSystem *_system;
TIM *_currentTim;
@@ -85,6 +119,19 @@ private:
bool _finished;
+ Common::String _vocFiles[120];
+
+ Animation _animations[TIM::kWSASlots];
+
+ Animation *initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags);
+
+ char _audioFilename[32];
+
+ uint8 *_langData;
+ char *getTableEntry(uint idx);
+ bool _textDisplayed;
+ uint8 *_textAreaBuffer;
+
int execCommand(int cmd, const uint16 *param);
typedef int (TIMInterpreter::*CommandProc)(const uint16 *);
@@ -98,8 +145,20 @@ private:
int cmd_initFunc0(const uint16 *param);
int cmd_stopCurFunc(const uint16 *param);
+ int cmd_initWSA(const uint16 *param);
+ int cmd_uninitWSA(const uint16 *param);
int cmd_initFunc(const uint16 *param);
int cmd_stopFunc(const uint16 *param);
+ int cmd_wsaDisplayFrame(const uint16 *param);
+ int cmd_displayText(const uint16 *param);
+ int cmd_loadVocFile(const uint16 *param);
+ int cmd_unloadVocFile(const uint16 *param);
+ int cmd_playVocFile(const uint16 *param);
+ int cmd_loadSoundFile(const uint16 *param);
+ int cmd_playMusicTrack(const uint16 *param);
+ int cmd_setLoopIp(const uint16 *param);
+ int cmd_continueLoop(const uint16 *param);
+ int cmd_resetLoopIp(const uint16 *param);
int cmd_resetAllRuntimes(const uint16 *param);
int cmd_execOpcode(const uint16 *param);
int cmd_initFuncNow(const uint16 *param);
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 169c319347..7915a33996 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -50,7 +50,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_sound->setSoundList(&_soundData[(startSeq > kSequenceZanfaun) ? kMusicFinale : kMusicIntro]);
_sound->loadSoundFile(0);
- _screen->_charWidth = -2;
+ _screen->_charWidth = (_flags.gameID == GI_LOL) ? 0 : -2;
memset(_activeWSA, 0, sizeof(ActiveWSA) * 8);
for (int i = 0; i < 8; ++i)
@@ -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();
@@ -300,8 +300,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_eventList.clear();
seqNum = kSequenceFirates;
}
- } else if (seqNum == kSequenceDemoFisher && !(_abortIntroFlag || skipFlag())) {
- seqNum = kSequenceDemoVirgin;
+ } else if (seqNum == endSeq && !(_abortIntroFlag || skipFlag())) {
+ seqNum = 0;
}
if (_menuChoice) {
@@ -1722,7 +1722,7 @@ int KyraEngine_HoF::seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
_seqScrollTextCounter = 0;
}
- seq_scrollPage();
+ seq_scrollPage(24, 144);
_seqFrameCounter++;
if (_seqFrameCounter < 0x256 || _seqFrameCounter > 0x31c) {
if (_seqFrameCounter < 0x174 || _seqFrameCounter > 0x1d7) {
@@ -1740,7 +1740,7 @@ int KyraEngine_HoF::seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
}
} else {
- seq_scrollPage();
+ seq_scrollPage(24, 144);
}
return 0;
}
@@ -1796,6 +1796,182 @@ int KyraEngine_HoF::seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
return frm;
}
+int KyraEngine_HoF::seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint8 *tmpPal = _screen->getPalette(2);
+
+ if (!(_seqFrameCounter % 100)) {
+ if (_seqFrameCounter == 0) {
+ _sound->haltTrack();
+ _sound->playTrack(6);
+ }
+ memcpy(tmpPal, _screen->getPalette(0), 0x300);
+ for (int i = 3; i < 0x300; i++) {
+ tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
+ if (tmpPal[i] > 0x3f)
+ tmpPal[i] = 0x3f;
+ }
+ seq_playTalkText(_rnd.getRandomBit());
+ _screen->setScreenPalette(tmpPal);
+ _screen->updateScreen();
+ delay(8);
+ } else {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->updateScreen();
+ if (_seqFrameCounter == 40)
+ seq_playTalkText(3);
+ }
+
+ _seqFrameCounter++;
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_seqFrameCounter - 17) {
+ case 0:
+ _seqFrameDelay = 8;
+ break;
+ case 3:
+ case 6:
+ case 9:
+ seq_playTalkText(8);
+ break;
+ case 15:
+ seq_playTalkText(9);
+ break;
+ case 18:
+ seq_playTalkText(2);
+ break;
+ default:
+ break;
+ }
+ _seqFrameCounter++;
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (_seqFrameCounter == 1)
+ seq_playTalkText(6);
+ else if (frm == 26)
+ seq_playTalkText(7);
+
+ _seqFrameCounter++;
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_seqFrameCounter) {
+ case 11:
+ case 14:
+ case 17:
+ case 20:
+ seq_playTalkText(8);
+ break;
+ case 22:
+ seq_playTalkText(11);
+ break;
+ case 24:
+ seq_playTalkText(8);
+ break;
+ case 30:
+ seq_playTalkText(15);
+ break;
+ case 34:
+ seq_playTalkText(14);
+ break;
+ case 38:
+ seq_playTalkText(13);
+ break;
+ case 42:
+ seq_playTalkText(12);
+ break;
+ default:
+ break;
+ }
+
+ _seqFrameCounter++;
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_seqFrameCounter++) {
+ case 0:
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 14:
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ seq_playTalkText(15);
+ break;
+ case 32:
+ seq_playTalkText(16);
+ break;
+ case 42:
+ seq_playTalkText(6);
+ break;
+ default:
+ break;
+ }
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (_seqFrameCounter++ == 100)
+ seq_playTalkText(5);
+ return frm;
+}
+
+int KyraEngine_HoF::seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ while (_seqScrollTextCounter < 0x122) {
+ _seqEndTime = _system->getMillis() + 6 * _tickLength;
+ if (!_seqFrameCounter) {
+ _screen->loadBitmap("adtext.cps", 4, 4, 0);
+ _screen->loadBitmap("adtext2.cps", 6, 6, 0);
+ _screen->copyPageMemory(6, 0, 4, 64000, 1024);
+ _screen->copyPageMemory(6, 1023, 6, 0, 64000);
+ _seqScrollTextCounter = 0;
+ }
+
+ if (_seqFrameCounter % 175) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ uint8 *tmpPal = _screen->getPalette(2);
+ memcpy(tmpPal, _screen->getPalette(0), 0x300);
+ for (int i = 3; i < 0x300; i++) {
+ tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
+ if (tmpPal[i] > 0x3f)
+ tmpPal[i] = 0x3f;
+ }
+ seq_playTalkText(_rnd.getRandomBit());
+ _screen->setScreenPalette(tmpPal);
+ _screen->updateScreen();
+ delay(8);
+ }
+
+ if (_seqFrameCounter == 40 || _seqFrameCounter == 80 || _seqFrameCounter == 150 || _seqFrameCounter == 300)
+ seq_playTalkText(3);
+
+ _screen->copyPage(12, 2);
+ seq_scrollPage(70, 130);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _seqFrameCounter++;
+ if (_seqFrameCounter < 128 || _seqFrameCounter > 207)
+ _seqScrollTextCounter++;
+ delayUntil(_seqEndTime);
+ }
+ _screen->copyPage(2, 12);
+
+ return 0;
+}
+
uint32 KyraEngine_HoF::seq_activeTextsTimeLeft() {
uint32 res = 0;
@@ -1892,16 +2068,14 @@ void KyraEngine_HoF::seq_sequenceCommand(int command) {
switch (command) {
case 0:
memset(pal, 0, 0x300);
- _screen->fadePalette(pal, 16);
+ _screen->fadePalette(pal, 36);
memcpy (_screen->getPalette(0), pal, 0x300);
memcpy (_screen->getPalette(1), pal, 0x300);
break;
case 1:
memset(pal, 0x3F, 0x300);
- //////////XXX
- //////////Unused anyway (at least by fm-towns intro/outro)
-
+ seq_playTalkText(_rnd.getRandomBit());
_screen->fadePalette(pal, 16);
memcpy (_screen->getPalette(0), pal, 0x300);
memcpy (_screen->getPalette(1), pal, 0x300);
@@ -2093,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) {
@@ -2293,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);
@@ -2575,32 +2749,34 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
delete[] textData;
}
-void KyraEngine_HoF::seq_scrollPage() {
+void KyraEngine_HoF::seq_scrollPage(int bottom, int top) {
int dstY, dstH, srcH;
static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
- if (_seqScrollTextCounter - 143 < 0) {
- dstY = 144 - _seqScrollTextCounter;
+ if (_seqScrollTextCounter - (top - 1) < 0) {
+ dstY = top - _seqScrollTextCounter;
dstH = _seqScrollTextCounter;
srcH = 0;
} else {
dstY = 0;
- srcH = _seqScrollTextCounter - 144;
- dstH = (400 - srcH <= 144) ? 400 - srcH : 144;
+ srcH = _seqScrollTextCounter - top;
+ dstH = (400 - srcH <= top) ? 400 - srcH : top;
}
if (dstH > 0) {
- for (int i = 0; i < 4; i++) {
- const ItemAnimData_v1 *def = &_demoAnimData[i];
- ActiveItemAnim *a = &_activeItemAnim[i];
-
- _screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
- _screen->drawShape(4, getShapePtr(def->itemIndex + def->frames[a->currentFrame]), 12, def->y - 8, 0, 0);
- if(_seqFrameCounter % 2 == 0)
- a->currentFrame = ++a->currentFrame % 20;
+ if (_demoAnimData) {
+ for (int i = 0; i < 4; i++) {
+ const ItemAnimData_v1 *def = &_demoAnimData[i];
+ ActiveItemAnim *a = &_activeItemAnim[i];
+
+ _screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
+ _screen->drawShape(4, getShapePtr(def->itemIndex + def->frames[a->currentFrame]), 12, def->y - 8, 0, 0);
+ if(_seqFrameCounter % 2 == 0)
+ a->currentFrame = ++a->currentFrame % 20;
+ }
}
- _screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + 24, 320, dstH, &d);
+ _screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
}
}
@@ -2654,8 +2830,15 @@ 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;
+
+ if (_flags.gameID == GI_LOL)
+ return;
+
if (_flags.isDemo && !_flags.isTalkie) {
_demoAnimData = _staticres->loadShapeAnimData_v1(k2SeqplayShapeAnimData, _itemAnimDataSize);
uint8 *shp = _res->fileData("icons.shp", 0);
@@ -2774,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.cpp b/engines/kyra/sound.cpp
index c8749dc06b..073639e4ca 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -104,6 +104,11 @@ int32 Sound::voicePlay(const char *file, bool isSfx) {
fileSize = 0;
}
+ if (!audioStream) {
+ warning("Couldn't load sound file '%s'", file);
+ return 0;
+ }
+
_soundChannels[h].file = file;
_mixer->playInputStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h].channelHandle, audioStream);
@@ -323,7 +328,17 @@ struct DeleterArray {
void SoundMidiPC::loadSoundFile(uint file) {
Common::StackLock lock(_mutex);
- Common::String filename = fileListEntry(file);
+ internalLoadFile(fileListEntry(file));
+}
+
+void SoundMidiPC::loadSoundFile(Common::String file) {
+ Common::StackLock lock(_mutex);
+
+ internalLoadFile(file);
+}
+
+void SoundMidiPC::internalLoadFile(Common::String file) {
+ Common::String filename = file;
filename += ".";
filename += _useC55 ? "C55" : "XMI";
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index cebfdf491f..2f7ac27ac5 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -120,6 +120,12 @@ public:
virtual void loadSoundFile(uint file) = 0;
/**
+ * Load a sound file for playing music
+ * and sound effects from.
+ */
+ virtual void loadSoundFile(Common::String file) = 0;
+
+ /**
* Plays the specified track.
*
* @param track track number
@@ -215,8 +221,6 @@ protected:
int _musicEnabled;
bool _sfxEnabled;
- int _currentTheme;
-
KyraEngine_v1 *_vm;
Audio::Mixer *_mixer;
@@ -260,6 +264,7 @@ public:
void process();
void loadSoundFile(uint file);
+ void loadSoundFile(Common::String file);
void playTrack(uint8 track);
void haltTrack();
@@ -269,6 +274,8 @@ public:
void beginFadeOut();
private:
+ void internalLoadFile(Common::String file);
+
void play(uint8 track);
void unk1();
@@ -280,7 +287,8 @@ private:
uint8 _trackEntries[500];
uint8 *_soundDataPtr;
int _sfxPlayingSound;
- uint _soundFileLoaded;
+
+ Common::String _soundFileLoaded;
uint8 _sfxPriority;
uint8 _sfxFourthByteOfSong;
@@ -316,6 +324,7 @@ public:
void updateVolumeSettings();
void loadSoundFile(uint file);
+ void loadSoundFile(Common::String file);
void playTrack(uint8 track);
void haltTrack();
@@ -343,6 +352,7 @@ public:
bool isMT32() const { return _nativeMT32; }
private:
+ void internalLoadFile(Common::String file);
void updateChannelVolume(uint8 vol);
static void onTimer(void *data);
@@ -397,6 +407,7 @@ public:
void process();
void loadSoundFile(uint file);
+ void loadSoundFile(Common::String) {}
void playTrack(uint8 track);
void haltTrack();
@@ -418,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:
@@ -454,6 +465,7 @@ public:
void process() {}
void loadSoundFile(uint file) {}
+ void loadSoundFile(Common::String) {}
void playTrack(uint8 track);
void haltTrack();
@@ -480,6 +492,7 @@ public:
void process();
void loadSoundFile(uint file) {}
+ void loadSoundFile(Common::String file);
void playTrack(uint8 track);
void haltTrack();
@@ -494,6 +507,7 @@ protected:
bool _useFmSfx;
uint8 *_musicTrackData;
+ uint8 *_sfxTrackData;
TownsPC98_OpnDriver *_driver;
};
@@ -513,6 +527,7 @@ public:
void setSoundList(const AudioDataStruct * list) { _music->setSoundList(list); _sfx->setSoundList(list); }
bool hasSoundFile(uint file) const { return _music->hasSoundFile(file) && _sfx->hasSoundFile(file); }
void loadSoundFile(uint file) { _music->loadSoundFile(file); _sfx->loadSoundFile(file); }
+ void loadSoundFile(Common::String file) { _music->loadSoundFile(file); _sfx->loadSoundFile(file); }
void playTrack(uint8 track) { _music->playTrack(track); }
void haltTrack() { _music->haltTrack(); }
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 68a2f0be9c..62551d2b09 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -235,6 +235,10 @@ private:
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
+ uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
+ //TODO: Check in LoL CD Adlib driver
+ if (offset == 0xFFFF)
+ return 0;
return _soundData + READ_LE_UINT16(_soundData + 2 * progId);
}
@@ -1282,6 +1286,9 @@ int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va
return 0;
uint8 *ptr = getProgram(value);
+ //TODO: Check in LoL CD Adlib driver
+ if (!ptr)
+ return 0;
uint8 chan = *ptr++;
uint8 priority = *ptr++;
@@ -2213,12 +2220,12 @@ const int SoundAdlibPC::_kyra1NumSoundTriggers = ARRAYSIZE(SoundAdlibPC::_kyra1S
SoundAdlibPC::SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
memset(_trackEntries, 0, sizeof(_trackEntries));
- _v2 = (_vm->gameFlags().gameID == GI_KYRA2);
+ _v2 = (_vm->gameFlags().gameID == GI_KYRA2) || (_vm->gameFlags().gameID == GI_LOL);
_driver = new AdlibDriver(mixer, _v2);
assert(_driver);
_sfxPlayingSound = -1;
- _soundFileLoaded = (uint)-1;
+ _soundFileLoaded.clear();
if (_v2) {
// TODO: Figure out if Kyra 2 uses sound triggers at all.
@@ -2262,7 +2269,7 @@ void SoundAdlibPC::playTrack(uint8 track) {
// sync for each loop. To avoid that, we declare that all four
// of the song channels have to jump "in sync".
- if (track == 4 && scumm_stricmp(fileListEntry(_soundFileLoaded), "KYRA1B") == 0)
+ if (track == 4 && _soundFileLoaded.equalsIgnoreCase("KYRA1B.ADL"))
_driver->setSyncJumpMask(0x000F);
else
_driver->setSyncJumpMask(0);
@@ -2341,6 +2348,15 @@ void SoundAdlibPC::beginFadeOut() {
}
void SoundAdlibPC::loadSoundFile(uint file) {
+ internalLoadFile(fileListEntry(file));
+}
+
+void SoundAdlibPC::loadSoundFile(Common::String file) {
+ internalLoadFile(file);
+}
+
+void SoundAdlibPC::internalLoadFile(Common::String file) {
+ file += ".ADL";
if (_soundFileLoaded == file)
return;
@@ -2349,12 +2365,9 @@ void SoundAdlibPC::loadSoundFile(uint file) {
uint8 *file_data = 0; uint32 file_size = 0;
- char filename[25];
- sprintf(filename, "%s.ADL", fileListEntry(file));
-
- file_data = _vm->resource()->fileData(filename, &file_size);
+ file_data = _vm->resource()->fileData(file.c_str(), &file_size);
if (!file_data) {
- warning("Couldn't find music file: '%s'", filename);
+ warning("Couldn't find music file: '%s'", file.c_str());
return;
}
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 0f2b916c9d..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 = (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 c05795dacd..bfffefb70a 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -23,16 +23,17 @@
*
*/
-
#include "common/endian.h"
#include "common/md5.h"
#include "kyra/kyra_v1.h"
#include "kyra/kyra_lok.h"
+#include "kyra/lol.h"
#include "kyra/kyra_v2.h"
#include "kyra/kyra_hof.h"
#include "kyra/kyra_mr.h"
#include "kyra/screen.h"
#include "kyra/screen_lok.h"
+#include "kyra/screen_lol.h"
#include "kyra/screen_hof.h"
#include "kyra/screen_mr.h"
#include "kyra/resource.h"
@@ -42,22 +43,22 @@
namespace Kyra {
-#define RESFILE_VERSION 28
+#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)
@@ -278,6 +279,16 @@ bool StaticResource::init() {
{ 0, 0, 0 }
};
+ static const FilenameTable lolStaticRes[] = {
+ // Demo Sequence Player
+ { k2SeqplayPakFiles, kStringList, "S_PAKFILES.TXT" },
+ { k2SeqplayStrings, kLanguageList, "S_STRINGS." },
+ { k2SeqplaySfxFiles, kStringList, "S_SFXFILES.TXT" },
+ { k2SeqplaySeqData, k2SeqData, "S_DATA.SEQ" },
+ { k2SeqplayIntroTracks, kStringList, "S_INTRO.TRA" },
+ { 0, 0, 0 }
+ };
+
if (_vm->game() == GI_KYRA1) {
_builtIn = 0;
_filenameTable = kyra1StaticRes;
@@ -287,33 +298,37 @@ bool StaticResource::init() {
} else if (_vm->game() == GI_KYRA3) {
_builtIn = 0;
_filenameTable = kyra3StaticRes;
+ } else if (_vm->game() == GI_LOL) {
+ if (!_vm->gameFlags().isDemo)
+ return true;
+ _builtIn = 0;
+ _filenameTable = lolStaticRes;
} else {
- error("unknown game ID");
+ error("StaticResource: Unknown game ID");
}
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);
@@ -537,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);
@@ -620,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;
@@ -635,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;
@@ -646,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;
@@ -664,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;
@@ -754,7 +762,7 @@ bool StaticResource::loadHofSequenceData(const char *filename, void *&ptr, int &
}
}
- delete[] filePtr;
+ delete file;
HofSeqData *loadTo = new HofSeqData;
assert(loadTo);
@@ -770,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;
}
@@ -904,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;
}
@@ -917,6 +914,8 @@ const char *StaticResource::getFilename(const char *name) {
filename += ".K2";
else if (_vm->gameFlags().gameID == GI_KYRA3)
filename += ".K3";
+ else if (_vm->gameFlags().gameID == GI_LOL)
+ filename += ".LOL";
if (_vm->gameFlags().isTalkie && _vm->gameFlags().gameID != GI_KYRA3)
filename += ".CD";
@@ -930,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 -
@@ -1034,38 +1030,51 @@ void KyraEngine_LoK::initStaticResource() {
}
// audio data tables
-#if 0
static const char *tIntro98[] = { "intro%d.dat" };
static const char *tIngame98[] = { "kyram%d.dat" };
-#endif
-
- static const AudioDataStruct soundData_PC[] = {
- { _soundFilesIntro, _soundFilesIntroSize, 0, 0 },
- { _soundFiles, _soundFilesSize, 0, 0 },
- { 0, 0, 0, 0}
- };
-
- static const AudioDataStruct soundData_TOWNS[] = {
- { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize },
- { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize },
- { 0, 0, 0, 0}
- };
-
-#if 0
- static const AudioDataStruct soundData_PC98[] = {
- { tIntro98, 1, 0, 0 },
- { tIngame98, 1, 0, 0 },
- { 0, 0, 0, 0}
- };
-#endif
-
- if (_flags.platform == Common::kPlatformPC)
- _soundData = soundData_PC;
- else if (_flags.platform == Common::kPlatformFMTowns)
- _soundData = soundData_TOWNS;
- else if (_flags.platform == Common::kPlatformPC98)
- _soundData = soundData_TOWNS/*soundData_PC98*/;
+ if (_flags.platform == Common::kPlatformPC) {
+ _soundData[0]._fileList = _soundFilesIntro;
+ _soundData[0]._fileListLen = _soundFilesIntroSize;
+ _soundData[0]._cdaTracks = 0;
+ _soundData[0]._cdaNumTracks = 0;
+ _soundData[1]._fileList = _soundFiles;
+ _soundData[1]._fileListLen = _soundFilesSize;
+ _soundData[1]._cdaTracks = 0;
+ _soundData[1]._cdaNumTracks = 0;
+ _soundData[2]._fileList = 0;
+ _soundData[2]._fileListLen = 0;
+ _soundData[2]._cdaTracks = 0;
+ _soundData[2]._cdaNumTracks = 0;
+ } else if (_flags.platform == Common::kPlatformFMTowns) {
+ _soundData[0]._fileList = _soundFiles;
+ _soundData[0]._fileListLen = _soundFilesSize;
+ _soundData[0]._cdaTracks = _cdaTrackTable;
+ _soundData[0]._cdaNumTracks = _cdaTrackTableSize;
+ _soundData[1]._fileList = _soundFiles;
+ _soundData[1]._fileListLen = _soundFilesSize;
+ _soundData[1]._cdaTracks = _cdaTrackTable;
+ _soundData[1]._cdaNumTracks = _cdaTrackTableSize;
+ _soundData[2]._fileList = 0;
+ _soundData[2]._fileListLen = 0;
+ _soundData[2]._cdaTracks = 0;
+ _soundData[2]._cdaNumTracks = 0;
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ _soundData[0]._fileList = tIntro98;
+ _soundData[0]._fileListLen = 1;
+ _soundData[0]._cdaTracks = 0;
+ _soundData[0]._cdaNumTracks = 0;
+ _soundData[1]._fileList = tIngame98;
+ _soundData[1]._fileListLen = 1;
+ _soundData[1]._cdaTracks = 0;
+ _soundData[1]._cdaNumTracks = 0;
+ _soundData[2]._fileList = 0;
+ _soundData[2]._fileListLen = 0;
+ _soundData[2]._cdaTracks = 0;
+ _soundData[2]._cdaNumTracks = 0;
+ } else {
+ memset(_soundData, 0, sizeof(_soundData));
+ }
}
void KyraEngine_LoK::loadMouseShapes() {
@@ -1263,38 +1272,50 @@ void KyraEngine_HoF::initStaticResource() {
static const char *fmtMusicFileListFinale[] = { "finale%d.twn" };
static const char *fmtMusicFileListIngame[] = { "km%02d.twn" };
-#if 0
static const char *pc98MusicFileListIntro[] = { "intro%d.86" };
static const char *pc98MusicFileListFinale[] = { "finale%d.86" };
static const char *pc98MusicFileListIngame[] = { "km%02d.86" };
-#endif
-
- static const AudioDataStruct soundData_PC[] = {
- { _musicFileListIntro, _musicFileListIntroSize, 0, 0 },
- { _musicFileListIngame, _musicFileListIngameSize, 0, 0},
- { _musicFileListFinale, _musicFileListIntroSize, 0, 0 }
- };
-
- static const AudioDataStruct soundData_TOWNS[] = {
- { fmtMusicFileListIntro, 1, _cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1 },
- { fmtMusicFileListIngame, 1, _cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1 },
- { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 }
- };
-#if 0
- static const AudioDataStruct soundData_PC98[] = {
- { pc98MusicFileListIntro, 1, 0, 0 },
- { pc98MusicFileListIngame, 1, 0, 0 },
- { pc98MusicFileListFinale, 1, 0, 0 }
- };
-#endif
-
- if (_flags.platform == Common::kPlatformPC)
- _soundData = soundData_PC;
- else if (_flags.platform == Common::kPlatformFMTowns)
- _soundData = soundData_TOWNS;
- else if (_flags.platform == Common::kPlatformPC98)
- _soundData = soundData_TOWNS/*soundData_PC98*/;
+ if (_flags.platform == Common::kPlatformPC) {
+ _soundData[0]._fileList = _musicFileListIntro;
+ _soundData[0]._fileListLen = _musicFileListIntroSize;
+ _soundData[0]._cdaTracks = 0;
+ _soundData[0]._cdaNumTracks = 0;
+ _soundData[1]._fileList = _musicFileListIngame;
+ _soundData[1]._fileListLen = _musicFileListIngameSize;
+ _soundData[1]._cdaTracks = 0;
+ _soundData[1]._cdaNumTracks = 0;
+ _soundData[2]._fileList = _musicFileListFinale;
+ _soundData[2]._fileListLen = _musicFileListIntroSize;
+ _soundData[2]._cdaTracks = 0;
+ _soundData[2]._cdaNumTracks = 0;
+ } else if (_flags.platform == Common::kPlatformFMTowns) {
+ _soundData[0]._fileList = fmtMusicFileListIntro;
+ _soundData[0]._fileListLen = 1;
+ _soundData[0]._cdaTracks = _cdaTrackTableIntro;
+ _soundData[0]._cdaNumTracks = _cdaTrackTableIntroSize >> 1;
+ _soundData[1]._fileList = fmtMusicFileListIngame;
+ _soundData[1]._fileListLen = 1;
+ _soundData[1]._cdaTracks = _cdaTrackTableIngame;
+ _soundData[1]._cdaNumTracks = _cdaTrackTableIngameSize >> 1;
+ _soundData[2]._fileList = fmtMusicFileListFinale;
+ _soundData[2]._fileListLen = 1;
+ _soundData[2]._cdaTracks = _cdaTrackTableFinale;
+ _soundData[2]._cdaNumTracks = _cdaTrackTableFinaleSize >> 1;
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ _soundData[0]._fileList = pc98MusicFileListIntro;
+ _soundData[0]._fileListLen = 1;
+ _soundData[0]._cdaTracks = 0;
+ _soundData[0]._cdaNumTracks = 0;
+ _soundData[1]._fileList = pc98MusicFileListIngame;
+ _soundData[1]._fileListLen = 1;
+ _soundData[1]._cdaTracks = 0;
+ _soundData[1]._cdaNumTracks = 0;
+ _soundData[2]._fileList = pc98MusicFileListFinale;
+ _soundData[2]._fileListLen = 1;
+ _soundData[2]._cdaTracks = 0;
+ _soundData[2]._cdaNumTracks = 0;
+ }
// setup sequence data
_sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize);
@@ -1333,8 +1354,17 @@ void KyraEngine_HoF::initStaticResource() {
&KyraEngine_HoF::seq_demoDig, 0
};
- _callbackS = (_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks;
- _callbackN = (_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks;
+ static const SeqProc lolDemoSequenceCallbacks[] = {
+ &KyraEngine_HoF::seq_lolDemoScene1, 0, &KyraEngine_HoF::seq_lolDemoScene2, 0,
+ &KyraEngine_HoF::seq_lolDemoScene3, 0, &KyraEngine_HoF::seq_lolDemoScene4, 0,
+ &KyraEngine_HoF::seq_lolDemoScene5, &KyraEngine_HoF::seq_lolDemoText5,
+ &KyraEngine_HoF::seq_lolDemoScene6, 0
+ };
+
+ static const SeqProc lolDemoNestedSequenceCallbacks[] = { 0 };
+
+ _callbackS = _flags.gameID == GI_LOL ? lolDemoSequenceCallbacks : ((_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks);
+ _callbackN = _flags.gameID == GI_LOL ? lolDemoNestedSequenceCallbacks : ((_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks);
}
void KyraEngine_MR::initStaticResource() {
@@ -2236,5 +2266,105 @@ const int8 KyraEngine_MR::_albumWSAY[] = {
-1, -2, 2, 2, -6, -6, -6, 0
};
+// lands of lore static res
+
+const ScreenDim Screen_LoL::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 }
+};
+
+const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable);
+
+const char * const LoLEngine::_languageExt[] = {
+ "ENG",
+ "FRE",
+ "GER"
+};
+
+const LoLEngine::CharacterPrev LoLEngine::_charPreviews[] = {
+ { "Ak\'shel", 0x060, 0x7F, { 0x0F, 0x08, 0x05 } },
+ { "Michael", 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } },
+ { "Kieran", 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } },
+ { "Conrad", 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } }
+};
+
+const uint8 LoLEngine::_chargenFrameTable[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12
+};
+
+const uint16 LoLEngine::_selectionPosTable[] = {
+ 0x6F, 0x00, 0x8F, 0x00, 0xAF, 0x00, 0xCF, 0x00,
+ 0xEF, 0x00, 0x6F, 0x20, 0x8F, 0x20, 0xAF, 0x20,
+ 0xCF, 0x20, 0xEF, 0x20, 0x6F, 0x40, 0x8F, 0x40,
+ 0xAF, 0x40, 0xCF, 0x40, 0xEF, 0x40, 0x10F, 0x00
+};
+
+const uint8 LoLEngine::_selectionChar1IdxTable[] = {
+ 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 5, 5,
+ 5, 5, 5
+};
+
+const uint8 LoLEngine::_selectionChar2IdxTable[] = {
+ 1, 1, 6, 6, 1, 1, 6, 6,
+ 6, 6, 6, 6, 6, 1, 1, 6,
+ 6, 6, 1, 1, 6, 6, 6, 6,
+ 6, 6, 6
+};
+
+const uint8 LoLEngine::_selectionChar3IdxTable[] = {
+ 2, 2, 7, 7, 7, 7, 2, 2,
+ 7, 7, 7, 7, 7, 7, 7, 2,
+ 2, 7, 7, 7, 7, 2, 2, 7,
+ 7, 7, 7
+};
+
+const uint8 LoLEngine::_selectionChar4IdxTable[] = {
+ 3, 3, 8, 8, 8, 8, 3, 3,
+ 8, 8, 3, 3, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 3, 3, 8,
+ 8, 8, 8
+};
+
+const uint8 LoLEngine::_reminderChar1IdxTable[] = {
+ 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5
+};
+
+const uint8 LoLEngine::_reminderChar2IdxTable[] = {
+ 9, 9, 9, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6
+};
+
+const uint8 LoLEngine::_reminderChar3IdxTable[] = {
+ 0xE, 0xE, 0xE, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7
+};
+
+const uint8 LoLEngine::_reminderChar4IdxTable[] = {
+ 0xF, 0xF, 0xF, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8
+};
+
+const uint8 LoLEngine::_selectionAnimIndexTable[] = {
+ 0, 5, 1, 6, 2, 7, 3, 8
+};
+
+const uint8 LoLEngine::_charInfoFrameTable[] = {
+ 0x0, 0x7, 0x8, 0x9, 0xA, 0xB, 0xA, 0x9,
+ 0x8, 0x7, 0x0, 0x0, 0x7, 0x8, 0x9, 0xA,
+ 0xB, 0xA, 0x9, 0x8, 0x7, 0x0, 0x0, 0x7,
+ 0x8, 0x9, 0xA, 0xB, 0xA, 0x9, 0x8, 0x7
+};
+
} // End of namespace Kyra
diff --git a/engines/kyra/text.cpp b/engines/kyra/text.cpp
index f8eb10a85e..eecb617942 100644
--- a/engines/kyra/text.cpp
+++ b/engines/kyra/text.cpp
@@ -29,7 +29,6 @@
#include "kyra/screen.h"
#include "kyra/text.h"
-#include "common/events.h"
#include "common/system.h"
#include "common/endian.h"
diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp
index dd587c5112..b94b8a6258 100644
--- a/engines/kyra/text_hof.cpp
+++ b/engines/kyra/text_hof.cpp
@@ -335,7 +335,7 @@ void KyraEngine_HoF::objectChatWaitToFinish() {
const uint32 endTime = _chatEndTime;
resetSkipFlag();
- while (running && !_quitFlag) {
+ while (running && !quit()) {
if (!_emc->isValid(&_chatScriptState))
_emc->start(&_chatScriptState, 1);
@@ -353,7 +353,7 @@ void KyraEngine_HoF::objectChatWaitToFinish() {
uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
- while (_system->getMillis() < nextFrame && !_quitFlag) {
+ while (_system->getMillis() < nextFrame && !quit()) {
updateWithText();
const uint32 curTime = _system->getMillis();
@@ -593,7 +593,7 @@ void KyraEngine_HoF::initTalkObject(int index) {
if (_currentTalkSections.STATim) {
_tim->resetFinishedFlag();
- while (!_quitFlag && !_tim->finished()) {
+ while (!quit() && !_tim->finished()) {
_tim->exec(_currentTalkSections.STATim, false);
if (_chatText)
updateWithText();
@@ -609,7 +609,7 @@ void KyraEngine_HoF::deinitTalkObject(int index) {
if (_currentTalkSections.ENDTim) {
_tim->resetFinishedFlag();
- while (!_quitFlag && !_tim->finished()) {
+ while (!quit() && !_tim->finished()) {
_tim->exec(_currentTalkSections.ENDTim, false);
if (_chatText)
updateWithText();
@@ -647,10 +647,10 @@ void KyraEngine_HoF::npcChatSequence(const char *str, int objectId, int vocHigh,
_chatVocHigh = _chatVocLow = -1;
}
- while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(_quitFlag || skipFlag())) {
+ while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(quit() || skipFlag())) {
if ((!speechEnabled() && chatAnimEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) {
_tim->resetFinishedFlag();
- while (!_tim->finished() && !skipFlag() && !_quitFlag) {
+ while (!_tim->finished() && !skipFlag() && !quit()) {
if (_currentTalkSections.TLKTim)
_tim->exec(_currentTalkSections.TLKTim, false);
else
diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp
index f6b0407a75..150ec59a23 100644
--- a/engines/kyra/text_lok.cpp
+++ b/engines/kyra/text_lok.cpp
@@ -120,8 +120,8 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const
if (event.kbd.keycode == '.')
_skipFlag = true;
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- quitGame();
runLoop = false;
break;
case Common::EVENT_LBUTTONDOWN:
diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp
index 16c56da099..be306ceec1 100644
--- a/engines/kyra/text_mr.cpp
+++ b/engines/kyra/text_mr.cpp
@@ -349,7 +349,7 @@ void KyraEngine_MR::objectChatWaitToFinish() {
const uint32 endTime = _chatEndTime;
resetSkipFlag();
- while (running && !_quitFlag) {
+ while (running && !quit()) {
if (!_emc->isValid(&_chatScriptState))
_emc->start(&_chatScriptState, 1);
@@ -367,7 +367,7 @@ void KyraEngine_MR::objectChatWaitToFinish() {
uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
- while (_system->getMillis() < nextFrame && !_quitFlag) {
+ while (_system->getMillis() < nextFrame && !quit()) {
updateWithText();
const uint32 curTime = _system->getMillis();
@@ -419,7 +419,7 @@ void KyraEngine_MR::badConscienceChatWaitToFinish() {
uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
int frame = _badConscienceFrameTable[_badConscienceAnim+24];
- while (running && !_quitFlag) {
+ while (running && !quit()) {
if (nextFrame < _system->getMillis()) {
++frame;
if (_badConscienceFrameTable[_badConscienceAnim+32] < frame)
@@ -477,7 +477,7 @@ void KyraEngine_MR::goodConscienceChatWaitToFinish() {
uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength;
int frame = _goodConscienceFrameTable[_goodConscienceAnim+15];
- while (running && !_quitFlag) {
+ while (running && !quit()) {
if (nextFrame < _system->getMillis()) {
++frame;
if (_goodConscienceFrameTable[_goodConscienceAnim+20] < frame)
@@ -597,7 +597,7 @@ void KyraEngine_MR::albumChatWaitToFinish() {
uint32 nextFrame = 0;
int frame = 12;
- while (running && !_quitFlag) {
+ while (running && !quit()) {
if (nextFrame < _system->getMillis()) {
++frame;
if (frame > 22)
diff --git a/engines/kyra/timer_mr.cpp b/engines/kyra/timer_mr.cpp
index 37a910ccf2..dd749723ce 100644
--- a/engines/kyra/timer_mr.cpp
+++ b/engines/kyra/timer_mr.cpp
@@ -65,7 +65,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) {
void KyraEngine_MR::timerFleaDeath(int arg) {
debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg);
_timer->setCountdown(4, 5400);
- saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME");
+ saveGame(getSavegameFilename(999), "Autosave", 0);
_screen->hideMouse();
_timer->disable(4);
runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1);
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp
index 3d18f27c7e..0f6440fd47 100644
--- a/engines/kyra/vqa.cpp
+++ b/engines/kyra/vqa.cpp
@@ -32,13 +32,13 @@
// The jung2.vqa movie does work, but only thanks to a grotesque hack.
-#include "common/events.h"
#include "common/system.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
#include "kyra/sound.h"
#include "kyra/screen.h"
#include "kyra/vqa.h"
+#include "kyra/resource.h"
namespace Kyra {
@@ -91,10 +91,10 @@ uint32 VQAMovie::readTag() {
// Some tags have to be on an even offset, so they are padded with a
// zero byte. Skip that.
- uint32 tag = _file.readUint32BE();
+ uint32 tag = _file->readUint32BE();
if (!(tag & 0xFF000000)) {
- tag = (tag << 8) | _file.readByte();
+ tag = (tag << 8) | _file->readByte();
}
return tag;
@@ -185,18 +185,19 @@ bool VQAMovie::open(const char *filename) {
debugC(9, kDebugLevelMovie, "VQAMovie::open('%s')", filename);
close();
- if (!_file.open(filename))
+ _file = _vm->resource()->getFileStream(filename);
+ if (!_file)
return false;
- if (_file.readUint32BE() != MKID_BE('FORM')) {
+ if (_file->readUint32BE() != MKID_BE('FORM')) {
warning("VQAMovie::open: Cannot find `FORM' tag");
return false;
}
// For now, we ignore the size of the FORM chunk.
- _file.readUint32BE();
+ _file->readUint32BE();
- if (_file.readUint32BE() != MKID_BE('WVQA')) {
+ if (_file->readUint32BE() != MKID_BE('WVQA')) {
warning("WQAMovie::open: Cannot find `WVQA' tag");
return false;
}
@@ -209,30 +210,30 @@ bool VQAMovie::open(const char *filename) {
while (!foundHeader || !foundFrameInfo) {
uint32 tag = readTag();
- uint32 size = _file.readUint32BE();
+ uint32 size = _file->readUint32BE();
switch (tag) {
case MKID_BE('VQHD'): // VQA header
- _header.version = _file.readUint16LE();
- _header.flags = _file.readUint16LE();
- _header.numFrames = _file.readUint16LE();
- _header.width = _file.readUint16LE();
- _header.height = _file.readUint16LE();
- _header.blockW = _file.readByte();
- _header.blockH = _file.readByte();
- _header.frameRate = _file.readByte();
- _header.cbParts = _file.readByte();
- _header.colors = _file.readUint16LE();
- _header.maxBlocks = _file.readUint16LE();
- _header.unk1 = _file.readUint32LE();
- _header.unk2 = _file.readUint16LE();
- _header.freq = _file.readUint16LE();
- _header.channels = _file.readByte();
- _header.bits = _file.readByte();
- _header.unk3 = _file.readUint32LE();
- _header.unk4 = _file.readUint16LE();
- _header.maxCBFZSize = _file.readUint32LE();
- _header.unk5 = _file.readUint32LE();
+ _header.version = _file->readUint16LE();
+ _header.flags = _file->readUint16LE();
+ _header.numFrames = _file->readUint16LE();
+ _header.width = _file->readUint16LE();
+ _header.height = _file->readUint16LE();
+ _header.blockW = _file->readByte();
+ _header.blockH = _file->readByte();
+ _header.frameRate = _file->readByte();
+ _header.cbParts = _file->readByte();
+ _header.colors = _file->readUint16LE();
+ _header.maxBlocks = _file->readUint16LE();
+ _header.unk1 = _file->readUint32LE();
+ _header.unk2 = _file->readUint16LE();
+ _header.freq = _file->readUint16LE();
+ _header.channels = _file->readByte();
+ _header.bits = _file->readByte();
+ _header.unk3 = _file->readUint32LE();
+ _header.unk4 = _file->readUint16LE();
+ _header.maxCBFZSize = _file->readUint32LE();
+ _header.unk5 = _file->readUint32LE();
// Kyrandia 3 uses version 1 VQA files, and is the only
// known game to do so. This version of the format has
@@ -302,7 +303,7 @@ bool VQAMovie::open(const char *filename) {
foundFrameInfo = true;
for (int i = 0; i < _header.numFrames; i++) {
- _frameInfo[i] = 2 * _file.readUint32LE();
+ _frameInfo[i] = 2 * _file->readUint32LE();
}
// HACK: This flag is set in jung2.vqa, and its
@@ -318,31 +319,31 @@ bool VQAMovie::open(const char *filename) {
// to the first VQFR chunk.
if (_frameInfo[0] & 0x01000000) {
- uint32 oldPos = _file.pos();
+ uint32 oldPos = _file->pos();
while (1) {
uint32 scanTag = readTag();
- uint32 scanSize = _file.readUint32BE();
+ uint32 scanSize = _file->readUint32BE();
- if (_file.eof())
+ if (_file->eos())
break;
if (scanTag == MKID_BE('VQFR')) {
- _frameInfo[0] = (_file.pos() - 8) | 0x80000000;
+ _frameInfo[0] = (_file->pos() - 8) | 0x80000000;
break;
}
- _file.seek(scanSize, SEEK_CUR);
+ _file->seek(scanSize, SEEK_CUR);
}
- _file.seek(oldPos);
+ _file->seek(oldPos);
}
break;
default:
warning("VQAMovie::open: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF));
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
}
}
@@ -373,8 +374,8 @@ void VQAMovie::close() {
_vectorPointers = NULL;
_stream = NULL;
- if (_file.isOpen())
- _file.close();
+ delete _file;
+ _file = 0;
freeBuffers();
@@ -391,13 +392,13 @@ void VQAMovie::displayFrame(uint frameNum) {
bool foundFrame = false;
uint i;
- _file.seek(_frameInfo[frameNum] & 0x7FFFFFFF);
+ _file->seek(_frameInfo[frameNum] & 0x7FFFFFFF);
while (!foundSound || !foundFrame) {
uint32 tag = readTag();
- uint32 size = _file.readUint32BE();
+ uint32 size = _file->readUint32BE();
- if (_file.eof()) {
+ if (_file->eos()) {
// This happens at the last frame. Apparently it has
// no sound?
break;
@@ -405,24 +406,24 @@ void VQAMovie::displayFrame(uint frameNum) {
byte *inbuf, *outbuf;
uint32 insize, outsize;
- uint32 end;
+ int32 end;
switch (tag) {
case MKID_BE('SND0'): // Uncompressed sound
foundSound = true;
inbuf = new byte[size];
- _file.read(inbuf, size);
+ _file->read(inbuf, size);
assert(_stream);
_stream->queueBuffer(inbuf, size);
break;
case MKID_BE('SND1'): // Compressed sound, almost like AUD
foundSound = true;
- outsize = _file.readUint16LE();
- insize = _file.readUint16LE();
+ outsize = _file->readUint16LE();
+ insize = _file->readUint16LE();
inbuf = new byte[insize];
- _file.read(inbuf, insize);
+ _file->read(inbuf, insize);
if (insize == outsize) {
assert(_stream);
@@ -439,50 +440,50 @@ void VQAMovie::displayFrame(uint frameNum) {
case MKID_BE('SND2'): // Compressed sound
foundSound = true;
warning("VQAMovie::displayFrame: `SND2' is not implemented");
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
case MKID_BE('VQFR'):
foundFrame = true;
- end = _file.pos() + size - 8;
+ end = _file->pos() + size - 8;
- while (_file.pos() < end) {
+ while (_file->pos() < end) {
tag = readTag();
- size = _file.readUint32BE();
+ size = _file->readUint32BE();
switch (tag) {
case MKID_BE('CBF0'): // Full codebook
- _file.read(_codeBook, size);
+ _file->read(_codeBook, size);
break;
case MKID_BE('CBFZ'): // Full codebook
inbuf = (byte *)allocBuffer(0, size);
- _file.read(inbuf, size);
+ _file->read(inbuf, size);
Screen::decodeFrame4(inbuf, _codeBook, _codeBookSize);
break;
case MKID_BE('CBP0'): // Partial codebook
_compressedCodeBook = false;
- _file.read(_partialCodeBook + _partialCodeBookSize, size);
+ _file->read(_partialCodeBook + _partialCodeBookSize, size);
_partialCodeBookSize += size;
_numPartialCodeBooks++;
break;
case MKID_BE('CBPZ'): // Partial codebook
_compressedCodeBook = true;
- _file.read(_partialCodeBook + _partialCodeBookSize, size);
+ _file->read(_partialCodeBook + _partialCodeBookSize, size);
_partialCodeBookSize += size;
_numPartialCodeBooks++;
break;
case MKID_BE('CPL0'): // Palette
assert(size <= 3 * 256);
- _file.read(_vm->screen()->_currentPalette, size);
+ _file->read(_vm->screen()->_currentPalette, size);
break;
case MKID_BE('CPLZ'): // Palette
inbuf = (byte *)allocBuffer(0, size);
- _file.read(inbuf, size);
+ _file->read(inbuf, size);
Screen::decodeFrame4(inbuf, _vm->screen()->_currentPalette, 768);
break;
@@ -490,14 +491,14 @@ void VQAMovie::displayFrame(uint frameNum) {
assert(size / 2 <= _numVectorPointers);
for (i = 0; i < size / 2; i++)
- _vectorPointers[i] = _file.readUint16LE();
+ _vectorPointers[i] = _file->readUint16LE();
break;
case MKID_BE('VPTZ'): // Frame data
inbuf = (byte *)allocBuffer(0, size);
outbuf = (byte *)allocBuffer(1, 2 * _numVectorPointers);
- _file.read(inbuf, size);
+ _file->read(inbuf, size);
size = Screen::decodeFrame4(inbuf, outbuf, 2 * _numVectorPointers);
assert(size / 2 <= _numVectorPointers);
@@ -508,7 +509,7 @@ void VQAMovie::displayFrame(uint frameNum) {
default:
warning("VQAMovie::displayFrame: Unknown `VQFR' sub-tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF));
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
}
@@ -518,7 +519,7 @@ void VQAMovie::displayFrame(uint frameNum) {
default:
warning("VQAMovie::displayFrame: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF));
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
}
}
@@ -593,11 +594,11 @@ void VQAMovie::play() {
uint32 insize, outsize;
if (_stream) {
- while (_file.pos() < (_frameInfo[0] & 0x7FFFFFFF)) {
+ while ((uint)_file->pos() < (_frameInfo[0] & 0x7FFFFFFF)) {
uint32 tag = readTag();
- uint32 size = _file.readUint32BE();
+ uint32 size = _file->readUint32BE();
- if (_file.eof()) {
+ if (_file->eos()) {
warning("VQAMovie::play: Unexpected EOF");
break;
}
@@ -605,16 +606,16 @@ void VQAMovie::play() {
switch (tag) {
case MKID_BE('SND0'): // Uncompressed sound
inbuf = new byte[size];
- _file.read(inbuf, size);
+ _file->read(inbuf, size);
_stream->queueBuffer(inbuf, size);
break;
case MKID_BE('SND1'): // Compressed sound
- outsize = _file.readUint16LE();
- insize = _file.readUint16LE();
+ outsize = _file->readUint16LE();
+ insize = _file->readUint16LE();
inbuf = new byte[insize];
- _file.read(inbuf, insize);
+ _file->read(inbuf, insize);
if (insize == outsize) {
_stream->queueBuffer(inbuf, insize);
@@ -628,17 +629,17 @@ void VQAMovie::play() {
case MKID_BE('SND2'): // Compressed sound
warning("VQAMovie::play: `SND2' is not implemented");
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
case MKID_BE('CMDS'): // Unused tag, always empty in kyra3
debugC(9, kDebugLevelMovie, "VQAMovie::play: skipping CMDS tag");
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
default:
warning("VQAMovie::play: Unknown tag `%c%c%c%c'", char((tag >> 24) & 0xFF), char((tag >> 16) & 0xFF), char((tag >> 8) & 0xFF), char(tag & 0xFF));
- _file.seek(size, SEEK_CUR);
+ _file->seek(size, SEEK_CUR);
break;
}
}
@@ -671,8 +672,8 @@ void VQAMovie::play() {
if (event.kbd.ascii == 27)
return;
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->quitGame();
return;
default:
break;
diff --git a/engines/kyra/vqa.h b/engines/kyra/vqa.h
index f600f008b7..46d3bd48fb 100644
--- a/engines/kyra/vqa.h
+++ b/engines/kyra/vqa.h
@@ -26,6 +26,8 @@
#ifndef KYRA_VQA_H
#define KYRA_VQA_H
+#include "common/stream.h"
+
class OSystem;
namespace Kyra {
@@ -98,7 +100,7 @@ protected:
void displayFrame(uint frameNum);
- Common::File _file;
+ Common::SeekableReadStream *_file;
VQAHeader _header;
uint32 *_frameInfo;
diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp
index 2af02b0374..f9f53b2806 100644
--- a/engines/lure/animseq.cpp
+++ b/engines/lure/animseq.cpp
@@ -44,12 +44,18 @@ AnimAbortType AnimationSequence::delay(uint32 milliseconds) {
while (g_system->getMillis() < delayCtr) {
while (events.pollEvent()) {
if ((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) {
- if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE) return ABORT_END_INTRO;
- else return ABORT_NEXT_SCENE;
- } else if (events.type() == Common::EVENT_LBUTTONDOWN)
+ if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE)
+ return ABORT_END_INTRO;
+ else
+ return ABORT_NEXT_SCENE;
+ } else if (events.type() == Common::EVENT_LBUTTONDOWN) {
return ABORT_NEXT_SCENE;
- else if (events.type() == Common::EVENT_QUIT)
+ } else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) {
return ABORT_END_INTRO;
+ } else if (events.type() == Common::EVENT_MAINMENU) {
+ return ABORT_NONE;
+ }
+
}
uint32 delayAmount = delayCtr - g_system->getMillis();
diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp
index 7dd1c77348..163d095243 100644
--- a/engines/lure/detection.cpp
+++ b/engines/lure/detection.cpp
@@ -26,6 +26,7 @@
#include "base/plugins.h"
#include "common/advancedDetector.h"
+#include "common/savefile.h"
#include "lure/lure.h"
@@ -184,9 +185,20 @@ public:
return "Lure of the Temptress (C) Revolution";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
};
+bool LureMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
bool LureMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Lure::LureGameDescription *gd = (const Lure::LureGameDescription *)desc;
if (gd) {
@@ -195,6 +207,44 @@ bool LureMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return gd != 0;
}
+SaveStateList LureMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ Common::String saveDesc;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ saveDesc = Lure::getSaveName(in);
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void LureMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".%03d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
#if PLUGIN_ENABLED_DYNAMIC(LURE)
REGISTER_PLUGIN_DYNAMIC(LURE, PLUGIN_TYPE_ENGINE, LureMetaEngine);
#else
diff --git a/engines/lure/events.cpp b/engines/lure/events.cpp
index 30e0e571b7..e244f69097 100644
--- a/engines/lure/events.cpp
+++ b/engines/lure/events.cpp
@@ -29,6 +29,7 @@
#include "graphics/cursorman.h"
#include "lure/events.h"
+#include "lure/lure.h"
#include "lure/res.h"
namespace Lure {
@@ -137,11 +138,12 @@ void Mouse::setPosition(int newX, int newY) {
void Mouse::waitForRelease() {
Events &e = Events::getReference();
+ LureEngine &engine = LureEngine::getReference();
do {
- while (e.pollEvent() && !e.quitFlag) ;
+ while (e.pollEvent() && !engine.quit()) ;
g_system->delayMillis(20);
- } while (!e.quitFlag && (lButton() || rButton() || mButton()));
+ } while (!engine.quit() && (lButton() || rButton() || mButton()));
}
/*--------------------------------------------------------------------------*/
@@ -150,7 +152,6 @@ static Events *int_events = NULL;
Events::Events() {
int_events = this;
- quitFlag = false;
}
Events &Events::getReference() {
@@ -163,10 +164,6 @@ bool Events::pollEvent() {
// Handle keypress
switch (_event.type) {
- case Common::EVENT_QUIT:
- quitFlag = true;
- break;
-
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
@@ -190,7 +187,7 @@ void Events::waitForPress() {
bool keyButton = false;
while (!keyButton) {
while (pollEvent()) {
- if (_event.type == Common::EVENT_QUIT) return;
+ if ((_event.type == Common::EVENT_QUIT) || (_event.type == Common::EVENT_RTL)) return;
else if ((_event.type == Common::EVENT_KEYDOWN) && (_event.kbd.ascii != 0))
keyButton = true;
else if ((_event.type == Common::EVENT_LBUTTONDOWN) ||
@@ -210,10 +207,11 @@ void Events::waitForPress() {
bool Events::interruptableDelay(uint32 milliseconds) {
Events &events = Events::getReference();
+ LureEngine &engine = LureEngine::getReference();
uint32 delayCtr = g_system->getMillis() + milliseconds;
while (g_system->getMillis() < delayCtr) {
- if (events.quitFlag) return true;
+ if (engine.quit()) return true;
if (events.pollEvent()) {
if (((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) ||
diff --git a/engines/lure/events.h b/engines/lure/events.h
index d1246f95d8..f04072aa0f 100644
--- a/engines/lure/events.h
+++ b/engines/lure/events.h
@@ -66,8 +66,6 @@ class Events {
private:
Common::Event _event;
public:
- bool quitFlag;
-
Events();
static Events &getReference();
diff --git a/engines/lure/fights.cpp b/engines/lure/fights.cpp
index dcf09ba50d..51fce850e6 100644
--- a/engines/lure/fights.cpp
+++ b/engines/lure/fights.cpp
@@ -22,6 +22,7 @@
#include "lure/fights.h"
#include "lure/luredefs.h"
#include "lure/game.h"
+#include "lure/lure.h"
#include "lure/res.h"
#include "lure/room.h"
#include "lure/sound.h"
@@ -108,15 +109,15 @@ bool FightsManager::isFighting() {
}
void FightsManager::fightLoop() {
+ LureEngine &engine = LureEngine::getReference();
Resources &res = Resources::getReference();
Game &game = Game::getReference();
Room &room = Room::getReference();
- Events &events = Events::getReference();
FighterRecord &playerFight = getDetails(PLAYER_ID);
uint32 timerVal = g_system->getMillis();
// Loop for the duration of the battle
- while (!events.quitFlag && (playerFight.fwhits != GENERAL_MAGIC_ID)) {
+ while (!engine.quit() && (playerFight.fwhits != GENERAL_MAGIC_ID)) {
checkEvents();
if (g_system->getMillis() > timerVal + GAME_FRAME_DELAY) {
@@ -184,6 +185,7 @@ const KeyMapping keyList[] = {
{Common::KEYCODE_INVALID, 0}};
void FightsManager::checkEvents() {
+ LureEngine &engine = LureEngine::getReference();
Game &game = Game::getReference();
Events &events = Events::getReference();
Mouse &mouse = Mouse::getReference();
@@ -196,7 +198,7 @@ void FightsManager::checkEvents() {
if (events.type() == Common::EVENT_KEYDOWN) {
switch (events.event().kbd.keycode) {
case Common::KEYCODE_ESCAPE:
- events.quitFlag = true;
+ engine.quitGame();
return;
case Common::KEYCODE_d:
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index f9b31c21c5..479877f229 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -23,10 +23,10 @@
*
*/
-#include "lure/lure.h"
#include "lure/game.h"
#include "lure/animseq.h"
#include "lure/fights.h"
+#include "lure/lure.h"
#include "lure/res_struct.h"
#include "lure/room.h"
#include "lure/scripts.h"
@@ -125,6 +125,7 @@ void Game::nextFrame() {
void Game::execute() {
OSystem &system = *g_system;
+ LureEngine &engine = LureEngine::getReference();
Room &room = Room::getReference();
Resources &res = Resources::getReference();
Events &events = Events::getReference();
@@ -137,12 +138,20 @@ void Game::execute() {
screen.empty();
screen.setPaletteEmpty();
+
+ bool _loadSavegame = false;
+
+ if (engine.gameToLoad() != -1)
+ _loadSavegame = engine.loadGame(engine.gameToLoad());
+
+ if (!_loadSavegame) {
+ // Flag for starting game
+ setState(GS_RESTART);
+ }
- // Flag for starting game
- setState(GS_RESTART);
bool initialRestart = true;
- while (!events.quitFlag) {
+ while (!engine.quit()) {
if ((_state & GS_RESTART) != 0) {
res.reset();
@@ -162,7 +171,7 @@ void Game::execute() {
mouse.cursorOn();
// Main game loop
- while (!events.quitFlag && ((_state & GS_RESTART) == 0)) {
+ while (!engine.quit() && ((_state & GS_RESTART) == 0)) {
// If time for next frame, allow everything to update
if (system.getMillis() > timerVal + GAME_FRAME_DELAY) {
timerVal = system.getMillis();
@@ -291,10 +300,7 @@ void Game::execute() {
if (restartFlag)
setState(GS_RESTART);
-
- } else if ((_state & GS_RESTART) == 0)
- // Exiting game
- events.quitFlag = true;
+ }
}
}
@@ -892,7 +898,7 @@ void Game::doShowCredits() {
void Game::doQuit() {
Sound.pause();
if (getYN())
- Events::getReference().quitFlag = true;
+ LureEngine::getReference().quitGame();
Sound.resume();
}
@@ -977,6 +983,7 @@ bool Game::getYN() {
Events &events = Events::getReference();
Screen &screen = Screen::getReference();
Resources &res = Resources::getReference();
+ LureEngine &engine = LureEngine::getReference();
Common::Language l = LureEngine::getReference().getLanguage();
Common::KeyCode y = Common::KEYCODE_y;
@@ -1018,7 +1025,7 @@ bool Game::getYN() {
}
g_system->delayMillis(10);
- } while (!events.quitFlag && !breakFlag);
+ } while (!engine.quit() && !breakFlag);
screen.update();
if (!vKbdFlag)
diff --git a/engines/lure/game.h b/engines/lure/game.h
index 5054074fb2..06dcee750f 100644
--- a/engines/lure/game.h
+++ b/engines/lure/game.h
@@ -27,6 +27,7 @@
#define LURE_GAME_H
+#include "common/config-manager.h"
#include "engines/engine.h"
#include "lure/luredefs.h"
#include "lure/menu.h"
@@ -85,8 +86,8 @@ public:
bool &debugFlag() { return _debugFlag; }
bool fastTextFlag() { return _fastTextFlag; }
bool soundFlag() { return _soundFlag; }
- uint8 sfxVolume() { return _sfxVolume; }
- uint8 musicVolume() { return _musicVolume; }
+ uint8 sfxVolume() { return ConfMan.getInt("sfx_volume"); }
+ uint8 musicVolume() { return ConfMan.getInt("music_volume"); }
Debugger &debugger() { return *_debugger; }
// Menu item support methods
diff --git a/engines/lure/intro.cpp b/engines/lure/intro.cpp
index 4d3e172dc5..b4cbf4a833 100644
--- a/engines/lure/intro.cpp
+++ b/engines/lure/intro.cpp
@@ -55,17 +55,18 @@ static const AnimRecord anim_screens[] = {
bool Introduction::showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize) {
Screen &screen = Screen::getReference();
- Events &events = Events::getReference();
bool isEGA = LureEngine::getReference().isEGA();
screen.screen().loadScreen(screenId);
screen.update();
Palette p(paletteId);
+ if (LureEngine::getReference().quit()) return true;
+
if (isEGA) screen.setPalette(&p);
else screen.paletteFadeIn(&p);
bool result = interruptableDelay(delaySize);
- if (events.quitFlag) return true;
+ if (LureEngine::getReference().quit()) return true;
if (!isEGA)
screen.paletteFadeOut();
@@ -83,6 +84,8 @@ bool Introduction::interruptableDelay(uint32 milliseconds) {
if (events.interruptableDelay(milliseconds)) {
if (events.type() == Common::EVENT_KEYDOWN)
return events.event().kbd.keycode == 27;
+ else if (LureEngine::getReference().quit())
+ return true;
else if (events.type() == Common::EVENT_LBUTTONDOWN)
return false;
}
diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp
index ea760ddb4f..8cd76cbc73 100644
--- a/engines/lure/lure.cpp
+++ b/engines/lure/lure.cpp
@@ -92,6 +92,7 @@ int LureEngine::init() {
_room = new Room();
_fights = new FightsManager();
+ _gameToLoad = -1;
_initialised = true;
return 0;
}
@@ -121,31 +122,38 @@ LureEngine &LureEngine::getReference() {
}
int LureEngine::go() {
-
- if (ConfMan.getBool("copy_protection")) {
- CopyProtectionDialog *dialog = new CopyProtectionDialog();
- bool result = dialog->show();
- delete dialog;
- if (_events->quitFlag)
- return 0;
-
- if (!result)
- error("Sorry - copy protection failed");
- }
-
Game *gameInstance = new Game();
+
+ // If requested, load a savegame instead of showing the intro
+ if (ConfMan.hasKey("save_slot")) {
+ _gameToLoad = ConfMan.getInt("save_slot");
+ if (_gameToLoad < 0 || _gameToLoad > 999)
+ _gameToLoad = -1;
+ }
+
+ if (_gameToLoad == -1) {
+ if (ConfMan.getBool("copy_protection")) {
+ CopyProtectionDialog *dialog = new CopyProtectionDialog();
+ bool result = dialog->show();
+ delete dialog;
+ if (quit())
+ return 0;
+
+ if (!result)
+ error("Sorry - copy protection failed");
+ }
- if (ConfMan.getInt("boot_param") == 0) {
- // Show the introduction
- Sound.loadSection(Sound.isRoland() ? ROLAND_INTRO_SOUND_RESOURCE_ID : ADLIB_INTRO_SOUND_RESOURCE_ID);
-
- Introduction *intro = new Introduction();
- intro->show();
- delete intro;
+ if (ConfMan.getInt("boot_param") == 0) {
+ // Show the introduction
+ Sound.loadSection(Sound.isRoland() ? ROLAND_INTRO_SOUND_RESOURCE_ID : ADLIB_INTRO_SOUND_RESOURCE_ID);
+ Introduction *intro = new Introduction();
+ intro->show();
+ delete intro;
+ }
}
// Play the game
- if (!_events->quitFlag) {
+ if (!quit()) {
// Play the game
Sound.loadSection(Sound.isRoland() ? ROLAND_MAIN_SOUND_RESOURCE_ID : ADLIB_MAIN_SOUND_RESOURCE_ID);
gameInstance->execute();
@@ -246,6 +254,10 @@ void LureEngine::GUIError(const char *msg, ...) {
Engine::GUIErrorMessage(buffer);
}
+void LureEngine::syncSoundSettings() {
+ Sound.syncSounds();
+}
+
Common::String *LureEngine::detectSave(int slotNumber) {
Common::ReadStream *f = this->_saveFileMan->openForLoading(
generateSaveName(slotNumber));
@@ -274,4 +286,23 @@ Common::String *LureEngine::detectSave(int slotNumber) {
return result;
}
+Common::String getSaveName(Common::InSaveFile *in) {
+ // Check for header
+ char saveName[MAX_DESC_SIZE];
+ char buffer[5];
+ in->read(&buffer[0], 5);
+ if (memcmp(&buffer[0], "lure", 5) == 0) {
+ // Check language version
+ in->readByte();
+ in->readByte();
+ char *p = saveName;
+ int decCtr = MAX_DESC_SIZE - 1;
+ while ((decCtr > 0) && ((*p++ = in->readByte()) != 0)) --decCtr;
+ *p = '\0';
+
+ }
+
+ return Common::String(saveName);
+}
+
} // End of namespace Lure
diff --git a/engines/lure/lure.h b/engines/lure/lure.h
index 1c5b40e54b..2c1a70329e 100644
--- a/engines/lure/lure.h
+++ b/engines/lure/lure.h
@@ -30,6 +30,7 @@
#include "common/rect.h"
#include "sound/mixer.h"
#include "common/file.h"
+#include "common/savefile.h"
#include "lure/disk.h"
#include "lure/res.h"
@@ -47,6 +48,7 @@ struct LureGameDescription;
class LureEngine : public Engine {
private:
bool _initialised;
+ int _gameToLoad;
uint8 _saveVersion;
Disk *_disk;
Resources *_resources;
@@ -70,9 +72,11 @@ public:
virtual int init();
virtual int go();
virtual void pauseEngineIntern(bool pause);
+ virtual void syncSoundSettings();
Disk &disk() { return *_disk; }
+ int gameToLoad() { return _gameToLoad; }
bool loadGame(uint8 slotNumber);
bool saveGame(uint8 slotNumber, Common::String &caption);
Common::String *detectSave(int slotNumber);
@@ -84,7 +88,7 @@ public:
Common::Platform getPlatform() const;
bool isEGA() const { return (getFeatures() & GF_EGA) != 0; }
};
-
+ Common::String getSaveName(Common::InSaveFile *in);
} // End of namespace Lure
#endif
diff --git a/engines/lure/menu.cpp b/engines/lure/menu.cpp
index 0b4ef06081..562f54da20 100644
--- a/engines/lure/menu.cpp
+++ b/engines/lure/menu.cpp
@@ -116,6 +116,7 @@ Menu &Menu::getReference() {
uint8 Menu::execute() {
OSystem &system = *g_system;
+ LureEngine &engine = LureEngine::getReference();
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
Screen &screen = Screen::getReference();
@@ -130,7 +131,7 @@ uint8 Menu::execute() {
while (mouse.lButton() || mouse.rButton()) {
while (events.pollEvent()) {
- if (events.quitFlag) return MENUITEM_NONE;
+ if (engine.quit()) return MENUITEM_NONE;
if (mouse.y() < MENUBAR_Y_SIZE) {
MenuRecord *p = getMenuAt(mouse.x());
@@ -467,6 +468,7 @@ Action PopupMenu::Show(int numEntries, Action *actions) {
uint16 PopupMenu::Show(int numEntries, const char *actions[]) {
if (numEntries == 0) return 0xffff;
+ LureEngine &engine = LureEngine::getReference();
Events &e = Events::getReference();
Mouse &mouse = Mouse::getReference();
OSystem &system = *g_system;
@@ -545,7 +547,7 @@ uint16 PopupMenu::Show(int numEntries, const char *actions[]) {
}
while (e.pollEvent()) {
- if (e.quitFlag) {
+ if (engine.quit()) {
selectedIndex = 0xffff;
goto bail_out;
diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp
index 7490f05b24..495f8046bb 100644
--- a/engines/lure/scripts.cpp
+++ b/engines/lure/scripts.cpp
@@ -26,6 +26,7 @@
#include "lure/animseq.h"
#include "lure/fights.h"
#include "lure/game.h"
+#include "lure/lure.h"
#include "lure/res.h"
#include "lure/room.h"
#include "lure/screen.h"
@@ -190,6 +191,7 @@ void Script::addSound(uint16 soundIndex, uint16 v2, uint16 v3) {
}
void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) {
+ LureEngine &engine = LureEngine::getReference();
Screen &screen = Screen::getReference();
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
@@ -219,7 +221,7 @@ void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) {
anim->show();
if (!events.interruptableDelay(30000)) {
// No key yet pressed, so keep waiting
- while (Sound.musicInterface_CheckPlaying(6) && !events.quitFlag) {
+ while (Sound.musicInterface_CheckPlaying(6) && !engine.quit()) {
if (events.interruptableDelay(20))
break;
}
@@ -227,7 +229,7 @@ void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) {
delete anim;
screen.paletteFadeOut();
- events.quitFlag = true;
+ engine.quitGame();
}
// Setup the pig fight in the cave
diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index 285f66e4e2..569058b282 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -220,10 +220,12 @@ void SoundManager::addSound(uint8 soundIndex, bool tidyFlag) {
newEntry->channel = channelCtr;
newEntry->numChannels = numChannels;
newEntry->flags = rec.flags;
+
if (_isRoland)
newEntry->volume = rec.volume;
else /* resource volumes do not seem to work well with our adlib emu */
newEntry->volume = 240; /* 255 causes clipping with adlib */
+
_activeSounds.push_back(SoundList::value_type(newEntry));
musicInterface_Play(rec.soundNumber, channelCtr, numChannels);
@@ -280,6 +282,23 @@ uint8 SoundManager::descIndexOf(uint8 soundNumber) {
return 0xff; // Couldn't find entry
}
+// Used to sync the volume for all channels with the Config Manager
+//
+void SoundManager::syncSounds() {
+ Game &game = Game::getReference();
+ musicInterface_TidySounds();
+
+ g_system->lockMutex(_soundMutex);
+ MusicListIterator i;
+ for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+ if ((*i)->isMusic())
+ (*i)->setVolume(game.musicVolume());
+ else
+ (*i)->setVolume(game.sfxVolume());
+ }
+ g_system->unlockMutex(_soundMutex);
+}
+
SoundDescResource *SoundManager::findSound(uint8 soundNumber) {
debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::findSound soundNumber=%d", soundNumber);
SoundListIterator i;
@@ -402,9 +421,8 @@ void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, u
return;
bool isMusic = (soundNumber & 0x80) != 0;
- uint8 volume = isMusic ? game.musicVolume() : game.sfxVolume();
- if (!game.soundFlag() || (volume == 0))
+ if (!game.soundFlag())
// Don't play sounds if sound is turned off
return;
@@ -563,12 +581,12 @@ void SoundManager::doTimer() {
/*------------------------------------------------------------------------*/
MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
- uint8 channelNum, uint8 soundNum, bool isMusic, uint8 numChannels, void *soundData, uint32 size) {
+ uint8 channelNum, uint8 soundNum, bool isMus, uint8 numChannels, void *soundData, uint32 size) {
_driver = driver;
_channels = channels;
_soundNumber = soundNum;
_channelNumber = channelNum;
- _isMusic = isMusic;
+ _isMusic = isMus;
_numChannels = numChannels;
_volume = 0;
@@ -576,7 +594,11 @@ MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
/* 90 is power on default for midi compliant devices */
_channels[_channelNumber + i].volume = 90;
}
- setVolume(240); /* 255 causes clipping with mastervol 192 and adlib */
+
+ if (_isMusic)
+ setVolume(ConfMan.getInt("music_volume"));
+ else
+ setVolume(ConfMan.getInt("sfx_volume"));
_passThrough = false;
diff --git a/engines/lure/sound.h b/engines/lure/sound.h
index c5a31a6c28..cf5dca7e96 100644
--- a/engines/lure/sound.h
+++ b/engines/lure/sound.h
@@ -66,7 +66,7 @@ private:
public:
MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
- uint8 channelNum, uint8 soundNum, bool isMusic, uint8 numChannels, void *soundData, uint32 size);
+ uint8 channelNum, uint8 soundNum, bool isMus, uint8 numChannels, void *soundData, uint32 size);
~MidiMusic();
void setVolume(int volume);
int getVolume() { return _volume; }
@@ -98,6 +98,7 @@ public:
uint8 channelNumber() { return _channelNumber; }
uint8 soundNumber() { return _soundNumber; }
bool isPlaying() { return _isPlaying; }
+ bool isMusic() {return _isMusic; }
};
class SoundManager: public Common::Singleton<SoundManager> {
@@ -142,6 +143,7 @@ public:
void stopSound(uint8 soundIndex);
void killSound(uint8 soundNumber);
void setVolume(uint8 soundNumber, uint8 volume);
+ void syncSounds();
void tidySounds();
uint8 descIndexOf(uint8 soundNumber);
SoundDescResource *findSound(uint8 soundNumber);
diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp
index 64394545d1..23cc9043cf 100644
--- a/engines/lure/surface.cpp
+++ b/engines/lure/surface.cpp
@@ -506,6 +506,7 @@ Surface *Surface::getScreen(uint16 resourceId) {
bool Surface::getString(Common::String &line, int maxSize, bool isNumeric, bool varLength, int16 x, int16 y) {
OSystem &system = *g_system;
+ LureEngine &engine = LureEngine::getReference();
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
Screen &screen = Screen::getReference();
@@ -533,7 +534,7 @@ bool Surface::getString(Common::String &line, int maxSize, bool isNumeric, bool
// Loop until the input string changes
refreshFlag = false;
while (!refreshFlag && !abortFlag) {
- abortFlag = events.quitFlag;
+ abortFlag = engine.quit();
if (abortFlag) break;
while (events.pollEvent()) {
@@ -975,7 +976,7 @@ bool SaveRestoreDialog::show(bool saveDialog) {
// Provide highlighting of lines to select a save slot
while (!abortFlag && !(mouse.lButton() && (selectedLine != -1))
&& !mouse.rButton() && !mouse.mButton()) {
- abortFlag = events.quitFlag;
+ abortFlag = engine.quit();
if (abortFlag) break;
while (events.pollEvent()) {
@@ -1178,7 +1179,7 @@ bool RestartRestoreDialog::show() {
// Event loop for making selection
bool buttonPressed = false;
- while (!events.quitFlag) {
+ while (!engine.quit()) {
// Handle events
while (events.pollEvent()) {
if ((events.type() == Common::EVENT_LBUTTONDOWN) && (highlightedButton != -1)) {
@@ -1230,7 +1231,7 @@ bool RestartRestoreDialog::show() {
Sound.killSounds();
- if (!restartFlag && !events.quitFlag) {
+ if (!restartFlag && !engine.quit()) {
// Need to show Restore game dialog
if (!SaveRestoreDialog::show(false))
// User cancelled, so fall back on Restart
@@ -1299,6 +1300,7 @@ bool CopyProtectionDialog::show() {
Screen &screen = Screen::getReference();
Events &events = Events::getReference();
Common::RandomSource rnd;
+ LureEngine &engine = LureEngine::getReference();
screen.setPaletteEmpty();
Palette p(COPY_PROTECTION_RESOURCE_ID - 1);
@@ -1349,7 +1351,7 @@ bool CopyProtectionDialog::show() {
// Clear any prior try
_charIndex = 0;
- while (!events.quitFlag) {
+ while (!engine.quit()) {
while (events.pollEvent() && (_charIndex < 4)) {
if (events.type() == Common::EVENT_KEYDOWN) {
if ((events.event().kbd.keycode == Common::KEYCODE_BACKSPACE) && (_charIndex > 0)) {
@@ -1383,7 +1385,7 @@ bool CopyProtectionDialog::show() {
break;
}
- if (events.quitFlag)
+ if (engine.quit())
return false;
// At this point, two page numbers have been entered - validate them
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index 5b8bdab9d6..11131783e2 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -406,10 +406,12 @@ void Converse::loadConversation(const char *convName) {
convS->read(buffer, 8);
if (debugFlag) printf("Conversation name: %s\n", buffer);
- while(!convS->eos()) {
+ while(true) {
chunkPos = convS->pos();
- if (debugFlag) printf("***** Pos: %i -> ", chunkPos);
chunk = convS->readUint32LE(); // read chunk
+ if (convS->eos()) break;
+
+ if (debugFlag) printf("***** Pos: %i -> ", chunkPos);
switch(chunk) {
case CHUNK_DECL: // Declare
if (debugFlag) printf("DECL chunk\n");
@@ -544,10 +546,10 @@ void Converse::loadConversation(const char *convName) {
curNode, _convNodes[curNode]->entries.size() - 1);
// Seek to chunk data (i.e. TEXT/MESG tag, which is usually right
// after this chunk but it can be further on in conditional reply chunks
- assert(data >= convS->pos());
+ assert((int)data >= convS->pos());
// If the entry's data is not right after the entry, remember the position
// to return to after the data is read
- if (chunk == CHUNK_CRPL && data != convS->pos())
+ if (chunk == CHUNK_CRPL && (int)data != convS->pos())
returnAddress = convS->pos();
convS->seek(data, SEEK_SET);
}
@@ -714,7 +716,7 @@ void Converse::loadConversationMads(const char *convName) {
printf("Chunk 0\n");
printf("Conv stream size: %i\n", convS->size());
- while(!convS->eos()) {
+ while(!convS->eos()) { // FIXME (eos changed)
printf("%i ", convS->readByte());
}
printf("\n");
@@ -725,7 +727,7 @@ void Converse::loadConversationMads(const char *convName) {
printf("Chunk 1\n");
printf("Conv stream size: %i\n", convS->size());
- while(!convS->eos()) {
+ while(!convS->eos()) { // FIXME (eos changed)
printf("%i ", convS->readByte());
}
printf("\n");
@@ -736,7 +738,7 @@ void Converse::loadConversationMads(const char *convName) {
printf("Chunk 2\n");
printf("Conv stream size: %i\n", convS->size());
- while(!convS->eos()) {
+ while(!convS->eos()) { // FIXME (eos changed)
printf("%i ", convS->readByte());
}
printf("\n");
@@ -790,7 +792,7 @@ void Converse::loadConversationMads(const char *convName) {
convS->read(buffer, 14); // speech file
printf("Speech file: %s\n", buffer);
- while(!convS->eos()) {
+ while(!convS->eos()) { // FIXME: eos changed
printf("%i ", convS->readByte());
}
printf("\n");
@@ -803,9 +805,12 @@ void Converse::loadConversationMads(const char *convName) {
printf("Chunk 1: conversation nodes\n");
printf("Conv stream size: %i\n", convS->size());
- while(!convS->eos()) {
+ while(true) {
+ uint16 id = convS->readUint16LE();
+ if (convS->eos()) break;
+
curEntry = new ConvEntry();
- curEntry->id = convS->readUint16LE();
+ curEntry->id = id;
curEntry->entryCount = convS->readUint16LE();
curEntry->flags = convS->readUint16LE();
if (curEntry->entryCount == 1 && curEntry->flags != 65535) {
@@ -839,10 +844,13 @@ void Converse::loadConversationMads(const char *convName) {
*buffer = 0;
- while(!convS->eos()) {
+ while(true) {
//if (curPos == 0)
// printf("%i: Offset %i: ", _convStrings.size(), convS->pos());
- buffer[curPos++] = convS->readByte();
+ uint8 b = convS->readByte();
+ if (convS->eos()) break;
+
+ buffer[curPos++] = b;
if (buffer[curPos - 1] == '~') { // filter out special characters
curPos--;
continue;
@@ -892,9 +900,12 @@ void Converse::loadConversationMads(const char *convName) {
//printf("Chunk 3 - MESG chunk data\n");
//printf("Conv stream size: %i\n", convS->size());
- while(!convS->eos()) {
+ while(true) {
+ uint16 index = convS->readUint16LE();
+ if (convS->eos()) break;
+
curMessage = new MessageEntry();
- stringIndex = convS->readUint16LE();
+ stringIndex = index;
stringCount = convS->readUint16LE();
*buffer = 0;
//printf("Message: %i\n", _madsMessageList.size());
@@ -915,7 +926,7 @@ void Converse::loadConversationMads(const char *convName) {
convS = convData.getItemStream(6);
printf("Chunk 6\n");
printf("Conv stream size: %i\n", convS->size());
- /*while(!convS->eos()) {
+ /*while(!convS->eos()) { // FIXME (eos changed)
printf("%i ", convS->readByte());
printf("%i ", convS->readByte());
printf("%i ", convS->readByte());
@@ -954,8 +965,10 @@ void Converse::readConvEntryActions(Common::SubReadStream *convS, ConvEntry *cur
int messageIndex = 0;
int unk = 0;
- while(!convS->eos()) {
+ while(true) {
chunk = convS->readByte();
+ if (convS->eos()) break;
+
type = convS->readByte();
switch (chunk) {
diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp
index 58c68979d1..98d007f67e 100644
--- a/engines/m4/globals.cpp
+++ b/engines/m4/globals.cpp
@@ -295,8 +295,11 @@ void Globals::loadMadsVocab() {
char buffer[30];
strcpy(buffer, "");
- while(!vocabS->eos()) {
- buffer[curPos++] = vocabS->readByte();
+ while(true) {
+ uint8 b = vocabS->readByte();
+ if (vocabS->eos()) break;
+
+ buffer[curPos++] = b;
if (buffer[curPos - 1] == '\0') {
// end of string, add it to the strings list
_madsVocab.push_back(strdup(buffer));
@@ -315,8 +318,11 @@ void Globals::loadMadsQuotes() {
char buffer[128];
strcpy(buffer, "");
- while(!quoteS->eos()) {
- buffer[curPos++] = quoteS->readByte();
+ while(true) {
+ uint8 b = quoteS->readByte();
+ if (quoteS->eos()) break;
+
+ buffer[curPos++] = b;
if (buffer[curPos - 1] == '\0') {
// end of string, add it to the strings list
_madsQuotes.push_back(strdup(buffer));
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index b2c0eda1ce..44d7f653d1 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -107,9 +107,9 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc) :
// FIXME
_vm = this;
- Common::File::addDefaultDirectory(_gameDataPath);
- Common::File::addDefaultDirectory("goodstuf");
- Common::File::addDefaultDirectory("resource");
+ Common::File::addDefaultDirectory(_gameDataDir);
+ Common::File::addDefaultDirectory("goodstuf"); // FIXME: This is nonsense
+ Common::File::addDefaultDirectory("resource"); // FIXME: This is nonsense
Common::addSpecialDebugLevel(kDebugScript, "script", "Script debug level");
Common::addSpecialDebugLevel(kDebugConversations, "conversations", "Conversations debugging");
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index c51daa84c4..71b45ca77c 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -247,15 +247,16 @@ void TextviewView::scriptDone() {
}
void TextviewView::processLines() {
+ _script->readLine_OLD(_currentLine, 79);
if (_script->eos())
error("Attempted to read past end of response file");
while (!_script->eos()) {
- _script->readLine(_currentLine, 79);
-
// Commented out line, so go loop for another
- if (_currentLine[0] == '#')
+ if (_currentLine[0] == '#') {
+ _script->readLine_OLD(_currentLine, 79);
continue;
+ }
// Process the line
char *cStart = strchr(_currentLine, '[');
@@ -284,6 +285,8 @@ void TextviewView::processLines() {
processText();
break;
}
+
+ _script->readLine_OLD(_currentLine, 79);
}
}
@@ -594,6 +597,7 @@ void AnimviewView::scriptDone() {
}
void AnimviewView::processLines() {
+ _script->readLine_OLD(_currentLine, 79);
if (_script->eos()) {
// end of script, end animation
scriptDone();
@@ -601,8 +605,6 @@ void AnimviewView::processLines() {
}
while (!_script->eos()) {
- _script->readLine(_currentLine, 79);
-
// Process the line
char *cStart = strchr(_currentLine, '-');
if (cStart) {
@@ -635,6 +637,8 @@ void AnimviewView::processLines() {
//printf("File: %s\n", _currentLine);
break;
}
+
+ _script->readLine_OLD(_currentLine, 79);
}
}
diff --git a/engines/m4/midi.cpp b/engines/m4/midi.cpp
index 51dd8654ae..3f1da2a369 100644
--- a/engines/m4/midi.cpp
+++ b/engines/m4/midi.cpp
@@ -269,7 +269,7 @@ byte *MidiPlayer::convertHMPtoSMF(byte *data, uint32 inSize, uint32 &outSize) {
byte lastCmd = 0;
// Now we can finally convert the track
- uint32 endPos = readS.pos() + trackLength;
+ int32 endPos = readS.pos() + trackLength;
while (readS.pos() < endPos) {
// Convert the VLQ
byte vlq[4];
diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp
index 5070a2b79c..265e4dae0b 100644
--- a/engines/m4/resource.cpp
+++ b/engines/m4/resource.cpp
@@ -76,11 +76,11 @@ FileSystem::FileSystem(const char *hashFilename) {
}
/* load hagfile records and update the list */
- while (!hashFile.eof()) {
+ while (!hashFile.eos()) {
HashHagEntry entry;
hashFile.read(entry.filename, kM4MaxFilenameSize);
entry.fileIndex = hashFile.readByte();
- if (hashFile.eof())
+ if (hashFile.eos())
break;
changeExtension(_hagEntries[entry.fileIndex].filename, entry.filename, "HAG");
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index e5870bfeec..354e5bbb86 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -350,7 +350,7 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
- const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const;
+ const Common::ADGameDescription *fallbackDetect(const Common::FSList *fslist) const;
};
@@ -362,7 +362,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return gd != 0;
}
-const Common::ADGameDescription *MadeMetaEngine::fallbackDetect(const FSList *fslist) const {
+const Common::ADGameDescription *MadeMetaEngine::fallbackDetect(const Common::FSList *fslist) const {
// Set the default values for the fallback descriptor's ADGameDescription part.
Made::g_fallbackDesc.desc.language = Common::UNK_LANG;
Made::g_fallbackDesc.desc.platform = Common::kPlatformPC;
diff --git a/engines/made/music.cpp b/engines/made/music.cpp
index c3b36d3b8c..0b58a11774 100644
--- a/engines/made/music.cpp
+++ b/engines/made/music.cpp
@@ -63,6 +63,8 @@ void MusicPlayer::setVolume(int volume) {
_masterVolume = volume;
+ Common::StackLock lock(_mutex);
+
for (int i = 0; i < 16; ++i) {
if (_channel[i]) {
_channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 831f1fab8e..6fe0f1c80d 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -95,13 +95,13 @@ void PmvPlayer::play(const char *filename) {
// get it to work well?
_audioStream = Audio::makeAppendableAudioStream(soundFreq, Audio::Mixer::FLAG_UNSIGNED);
- while (!_abort && !_fd->eof()) {
+ while (!_abort && !_fd->eos()) {
int32 frameTime = _vm->_system->getMillis();
readChunk(chunkType, chunkSize);
- if (_fd->eof())
+ if (_fd->eos())
break;
frameData = new byte[chunkSize];
diff --git a/engines/made/redreader.cpp b/engines/made/redreader.cpp
index 287574c312..a61d122041 100644
--- a/engines/made/redreader.cpp
+++ b/engines/made/redreader.cpp
@@ -55,9 +55,11 @@ Common::MemoryReadStream *RedReader::loadFromRed(const char *redFilename, const
bool RedReader::seekFile(Common::File &fd, FileEntry &fileEntry, const char *filename) {
char arcFilename[13];
- while (!fd.eof()) {
+ while (true) {
fd.skip(8); // skip unknown
fileEntry.compSize = fd.readUint32LE();
+ if (fd.eos()) break;
+
fileEntry.origSize = fd.readUint32LE();
fd.skip(10); // skip unknown
fd.read(arcFilename, 13);
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index 0c22d40259..38a4baffc5 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -174,13 +174,15 @@ void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 f
if (_vm->getGameID() != GID_RTZ)
maskp = (byte*)_maskDrawCtx.destSurface->getBasePtr(x, y);
- int32 sourcePitch, linePtrAdd;
+ int32 sourcePitch, linePtrAdd, sourceAdd;
byte *linePtr;
if (flipX) {
linePtrAdd = -1;
+ sourceAdd = sourceSurface->w;
} else {
linePtrAdd = 1;
+ sourceAdd = 0;
}
if (flipY) {
@@ -191,11 +193,7 @@ void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 f
}
for (int16 yc = 0; yc < clipHeight; yc++) {
- if (flipX) {
- linePtr = source + sourceSurface->w;
- } else {
- linePtr = source;
- }
+ linePtr = source + sourceAdd;
for (int16 xc = 0; xc < clipWidth; xc++) {
if (*linePtr && (_vm->getGameID() == GID_RTZ || (mask == 0 || maskp[xc] == 0))) {
if (*linePtr)
@@ -688,7 +686,7 @@ void Screen::printText(const char *text) {
for (int textPos = 0; textPos < textLen; textPos++) {
- uint c = ((byte*)text)[textPos];
+ uint c = ((const byte*)text)[textPos];
int charWidth = _font->getCharWidth(c);
if (c == 9) {
@@ -806,7 +804,12 @@ void Screen::showWorkScreen() {
void Screen::updateScreenAndWait(int delay) {
_vm->_system->updateScreen();
- _vm->_system->delayMillis(delay);
+ uint32 startTime = _vm->_system->getMillis();
+ while (_vm->_system->getMillis() < startTime + delay) {
+ _vm->handleEvents();
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(5);
+ }
}
int16 Screen::addToSpriteList(int16 index, int16 xofs, int16 yofs) {
diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp
index ee96af601a..6e9cf5c01a 100644
--- a/engines/made/screenfx.cpp
+++ b/engines/made/screenfx.cpp
@@ -132,7 +132,7 @@ void ScreenEffects::setBlendedPalette(byte *palette, byte *newPalette, int color
if (!_screen->isPaletteLocked()) {
int32 mulValue = (value * 64) / maxValue;
for (int i = 0; i < colorCount * 3; i++)
- _fxPalette[i] = CLIP(newPalette[i] - (newPalette[i] - palette[i]) * mulValue / 64, 0, 255);
+ _fxPalette[i] = CLIP<int32>(newPalette[i] - (newPalette[i] - palette[i]) * mulValue / 64, 0, 255);
_screen->setRGBPalette(_fxPalette, 0, 256);
}
}
diff --git a/engines/metaengine.h b/engines/metaengine.h
index aef860e0f9..3a9f930eec 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -28,14 +28,17 @@
#include "common/scummsys.h"
#include "common/str.h"
#include "common/error.h"
-#include "common/fs.h"
-#include "base/game.h"
+#include "engines/game.h"
#include "base/plugins.h"
class Engine;
class OSystem;
+namespace Common {
+ class FSList;
+}
+
/**
* A meta engine is essentially a factory for Engine instances with the
* added ability of listing and detecting supported games.
@@ -62,7 +65,7 @@ public:
* (possibly empty) list of games supported by the engine which it was able
* to detect amongst the given files.
*/
- virtual GameList detectGames(const FSList &fslist) const = 0;
+ virtual GameList detectGames(const Common::FSList &fslist) const = 0;
/**
* Tries to instantiate an engine instance based on the settings of
@@ -79,9 +82,9 @@ public:
/**
* Return a list of all save states associated with the given target.
*
- * In general, the caller will already have ensured that this (Meta)Engine
- * is responsible for the specified target by using findGame on it resp.
- * on the associated gameid from the relevant ConfMan entry, if present.
+ * The caller has to ensure that this (Meta)Engine is responsible
+ * for the specified target (by using findGame on it respectively
+ * on the associated gameid from the relevant ConfMan entry, if present).
*
* The default implementation returns an empty list.
*
@@ -91,6 +94,92 @@ public:
virtual SaveStateList listSaves(const char *target) const {
return SaveStateList();
}
+
+ /**
+ * Remove the specified save state.
+ *
+ * For most engines this just amounts to calling _saveFileMan->removeSaveFile().
+ * Engines which keep an index file will also update it accordingly.
+ *
+ * @param target name of a config manager target
+ * @param slot slot number of the save state to be removed
+ */
+ virtual void removeSaveState(const char *target, int slot) const {};
+
+ /**
+ * Returns meta infos from the specified save state.
+ *
+ * Depending on the MetaEngineFeatures set this can include
+ * thumbnails, save date / time, play time.
+ *
+ * @param target name of a config manager target
+ * @param slot slot number of the save state
+ */
+ virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const { return SaveStateDescriptor(); }
+
+ /** @name MetaEngineFeature flags */
+ //@{
+
+ /**
+ * A feature in this context means an ability of the engine which can be
+ * either available or not.
+ */
+ enum MetaEngineFeature {
+ /** 'Return to launcher' feature (i.e. EVENT_RTL is handled) */
+ kSupportsRTL = 0,
+
+ /**
+ * Listing Save States (i.e. implements the listSaves() method;
+ * used for --list-saves support)
+ */
+ kSupportsListSaves = 1,
+
+ /** Loading from the Launcher / command line (-x) */
+ kSupportsDirectLoad = 2,
+
+ /**
+ * Deleting Saves from the Launcher (i.e. implements the
+ * removeSaveState() method)
+ */
+ kSupportsDeleteSave = 3,
+
+ /**
+ * Features meta infos for savestates (i.e. implements the
+ * querySaveMetaInfos method properly)
+ */
+ kSupportsMetaInfos = 4,
+
+ /**
+ * Features a thumbnail in savegames (i.e. includes a thumbnail
+ * in savestates returned via querySaveMetaInfo).
+ * This flag may only be set when 'kSupportsMetaInfos' is set.
+ */
+ kSupportsThumbnails = 5,
+
+ /**
+ * Features 'save_date' and 'save_time' entries in the
+ * savestate returned by querySaveMetaInfo. Those values
+ * indicate the date/time the savegame was created.
+ * This flag may only be set when 'kSupportsMetaInfos' is set.
+ */
+ kSupportsSaveDate = 6,
+
+ /**
+ * Features 'play_time' entry in the savestate returned by
+ * querySaveMetaInfo. It indicates how long the user played
+ * the game till the save.
+ * This flag may only be set when 'kSupportsMetaInfos' is set.
+ */
+ kSupportsSavePlayTime = 7
+ };
+
+ /**
+ * Determine whether the engine supports the specified MetaEngine feature.
+ * Used by e.g. the launcher to determine whether to enable the "Load" button.
+ */
+ virtual bool hasFeature(MetaEngineFeature f) const { return false; };
+
+ //@}
};
@@ -107,7 +196,7 @@ private:
public:
GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
- GameList detectGames(const FSList &fslist) const;
+ GameList detectGames(const Common::FSList &fslist) const;
const EnginePlugin::List &getPlugins() const;
};
diff --git a/engines/module.mk b/engines/module.mk
index 6cfe9b36fa..8102046c5b 100644
--- a/engines/module.mk
+++ b/engines/module.mk
@@ -1,7 +1,9 @@
MODULE := engines
MODULE_OBJS := \
- engine.o
+ dialogs.o \
+ engine.o \
+ game.o
# Include common rules
include $(srcdir)/rules.mk
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
index 81b32adb15..290aa5e625 100644
--- a/engines/parallaction/balloons.cpp
+++ b/engines/parallaction/balloons.cpp
@@ -30,6 +30,183 @@
namespace Parallaction {
+class WrappedLineFormatter {
+
+protected:
+ Common::String _line;
+ Font *_font;
+ uint16 _lines, _lineWidth;
+
+ virtual void setup() = 0;
+ virtual void action() = 0;
+ virtual void end() = 0;
+ virtual Common::String expand(const Common::String &token) { return token; }
+
+ void textAccum(const Common::String &token, uint16 width) {
+ if (token.empty()) {
+ return;
+ }
+
+ _lineWidth += width;
+ _line += token;
+ }
+
+ void textNewLine() {
+ _lines++;
+ _lineWidth = 0;
+ _line.clear();
+ }
+
+public:
+ WrappedLineFormatter(Font *font) : _font(font) { }
+ virtual ~WrappedLineFormatter() { }
+
+ virtual void calc(const char *text, uint16 maxwidth) {
+ setup();
+
+ _lineWidth = 0;
+ _line.clear();
+ _lines = 0;
+
+ Common::StringTokenizer tokenizer(text, " ");
+ Common::String token;
+ Common::String blank(" ");
+
+ uint16 blankWidth = _font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ while (!tokenizer.empty()) {
+ token = tokenizer.nextToken();
+ token = expand(token);
+
+ if (token == '/') {
+ tokenWidth = 0;
+ action();
+ textNewLine();
+ } else {
+ // todo: expand '%'
+ tokenWidth = _font->getStringWidth(token.c_str());
+
+ if (_lineWidth == 0) {
+ textAccum(token, tokenWidth);
+ } else {
+ if (_lineWidth + blankWidth + tokenWidth <= maxwidth) {
+ textAccum(blank, blankWidth);
+ textAccum(token, tokenWidth);
+ } else {
+ action();
+ textNewLine();
+ textAccum(token, tokenWidth);
+ }
+ }
+ }
+ }
+
+ end();
+ }
+};
+
+class StringExtent_NS : public WrappedLineFormatter {
+
+ uint _width, _height;
+
+protected:
+ virtual Common::String expand(const Common::String &token) {
+ if (token.compareToIgnoreCase("%p") == 0) {
+ return Common::String("/");
+ }
+
+ return token;
+ }
+
+ virtual void setup() {
+ _width = _height = 0;
+
+ _line.clear();
+ _lines = 0;
+ _width = 0;
+ }
+
+ virtual void action() {
+ if (_lineWidth > _width) {
+ _width = _lineWidth;
+ }
+ _height = _lines * _font->height();
+ }
+
+ virtual void end() {
+ action();
+ }
+
+public:
+ StringExtent_NS(Font *font) : WrappedLineFormatter(font) { }
+
+ uint width() const { return _width; }
+ uint height() const { return _height; }
+};
+
+
+class StringWriter_NS : public WrappedLineFormatter {
+
+ uint _width, _height;
+ byte _color;
+
+ Graphics::Surface *_surf;
+
+protected:
+ virtual Common::String expand(const Common::String& token) {
+ if (token.compareToIgnoreCase("%p") == 0) {
+ Common::String t(".......");
+ for (int i = 0; _password[i]; i++) {
+ t.setChar(_password[i], i);
+ }
+ return Common::String("> ") + t;
+ } else
+ if (token.compareToIgnoreCase("%s") == 0) {
+ char buf[20];
+ sprintf(buf, "%i", _score);
+ return Common::String(buf);
+ }
+
+ return token;
+ }
+
+ virtual void setup() {
+ }
+
+ virtual void action() {
+ if (_line.empty()) {
+ return;
+ }
+ uint16 rx = 10;
+ uint16 ry = 4 + _lines * _font->height(); // y
+
+ byte *dst = (byte*)_surf->getBasePtr(rx, ry);
+ _font->setColor(_color);
+ _font->drawString(dst, _surf->w, _line.c_str());
+ }
+
+ virtual void end() {
+ action();
+ }
+
+public:
+ StringWriter_NS(Font *font) : WrappedLineFormatter(font) { }
+
+ void write(const char *text, uint maxWidth, byte color, Graphics::Surface *surf) {
+ StringExtent_NS se(_font);
+ se.calc(text, maxWidth);
+ _width = se.width() + 10;
+ _height = se.height() + 20;
+ _color = color;
+ _surf = surf;
+
+ calc(text, maxWidth);
+ }
+
+};
+
+
#define BALLOON_TRANSPARENT_COLOR_NS 2
#define BALLOON_TRANSPARENT_COLOR_BR 0
@@ -69,6 +246,8 @@ class BalloonManager_ns : public BalloonManager {
static int16 _dialogueBalloonX[5];
+ byte _textColors[2];
+
struct Balloon {
Common::Rect outerBox;
Common::Rect innerBox;
@@ -78,8 +257,6 @@ class BalloonManager_ns : public BalloonManager {
uint _numBalloons;
- void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height);
- void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
Balloon *getBalloon(uint id);
@@ -91,16 +268,18 @@ public:
void freeBalloons();
int setLocationBalloon(char *text, bool endGame);
- int setDialogueBalloon(char *text, uint16 winding, byte textColor);
- int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
- void setBalloonText(uint id, char *text, byte textColor);
+ int setDialogueBalloon(char *text, uint16 winding, TextColor textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor);
+ void setBalloonText(uint id, char *text, TextColor textColor);
int hitTestDialogueBalloon(int x, int y);
};
int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };
BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) {
-
+ _textColors[kSelectedColor] = 0;
+ _textColors[kUnselectedColor] = 3;
+ _textColors[kNormalColor] = 0;
}
BalloonManager_ns::~BalloonManager_ns() {
@@ -139,7 +318,7 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor
winding = (winding == 0 ? 1 : 0);
Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);
s.moveTo(r.width()/2 - 5, r.bottom - 1);
- _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS);
+ _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_NS);
}
_numBalloons++;
@@ -148,16 +327,20 @@ int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 bor
}
-int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) {
int16 w, h;
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ StringExtent_NS se(_vm->_dialogueFont);
+ se.calc(text, MAX_BALLOON_WIDTH);
+ w = se.width() + 14;
+ h = se.height() + 20;
int id = createBalloon(w+5, h, winding, 1);
Balloon *balloon = &_intBalloons[id];
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ StringWriter_NS sw(_vm->_dialogueFont);
+ sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);
// TODO: extract some text to make a name for obj
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
@@ -168,16 +351,21 @@ int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
return id;
}
-int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) {
int16 w, h;
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ StringExtent_NS se(_vm->_dialogueFont);
+ se.calc(text, MAX_BALLOON_WIDTH);
+ w = se.width() + 14;
+ h = se.height() + 20;
+
int id = createBalloon(w+5, h, winding, 1);
Balloon *balloon = &_intBalloons[id];
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ StringWriter_NS sw(_vm->_dialogueFont);
+ sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);
// TODO: extract some text to make a name for obj
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
@@ -193,10 +381,12 @@ int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textC
return id;
}
-void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) {
+void BalloonManager_ns::setBalloonText(uint id, char *text, TextColor textColor) {
Balloon *balloon = getBalloon(id);
balloon->surface->fillRect(balloon->innerBox, 1);
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ StringWriter_NS sw(_vm->_dialogueFont);
+ sw.write(text, MAX_BALLOON_WIDTH, _textColors[textColor], balloon->surface);
}
@@ -204,11 +394,15 @@ int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) {
int16 w, h;
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ StringExtent_NS se(_vm->_dialogueFont);
+ se.calc(text, MAX_BALLOON_WIDTH);
+ w = se.width() + 14;
+ h = se.height() + 20;
int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS);
Balloon *balloon = &_intBalloons[id];
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
+ StringWriter_NS sw(_vm->_dialogueFont);
+ sw.write(text, MAX_BALLOON_WIDTH, _textColors[kNormalColor], balloon->surface);
// TODO: extract some text to make a name for obj
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
@@ -245,112 +439,105 @@ void BalloonManager_ns::freeBalloons() {
_numBalloons = 0;
}
-void BalloonManager_ns::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
-
- uint16 lines = 0;
- uint16 linewidth = 0;
- uint16 rx = 10;
- uint16 ry = 4;
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
- char token[MAX_TOKEN_LEN];
- if (wrapwidth == -1)
- wrapwidth = _vm->_screenWidth;
- while (strlen(text) > 0) {
- text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
- if (!scumm_stricmp(token, "%p")) {
- lines++;
- rx = 10;
- ry = 4 + lines*10; // y
- strcpy(token, "> .......");
- strncpy(token+2, _password, strlen(_password));
- tokenWidth = font->getStringWidth(token);
- } else {
- tokenWidth = font->getStringWidth(token);
- linewidth += tokenWidth;
- if (linewidth > wrapwidth) {
- // wrap line
- lines++;
- rx = 10; // x
- ry = 4 + lines*10; // y
- linewidth = tokenWidth;
- }
+class StringExtent_BR : public WrappedLineFormatter {
- if (!scumm_stricmp(token, "%s")) {
- sprintf(token, "%d", _score);
- }
+ uint _width, _height;
- }
+protected:
+ virtual void setup() {
+ _width = _height = 0;
- _gfx->drawText(font, surf, rx, ry, token, color);
+ _line.clear();
+ _lines = 0;
+ _width = 0;
+ }
- rx += tokenWidth + blankWidth;
- linewidth += blankWidth;
+ virtual void action() {
+ if (_lineWidth > _width) {
+ _width = _lineWidth;
+ }
+ _height = _lines * _font->height();
+ }
- text = Common::ltrim(text);
+ virtual void end() {
+ action();
}
-}
+public:
+ StringExtent_BR(Font *font) : WrappedLineFormatter(font) { }
-void BalloonManager_ns::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) {
+ uint width() const { return _width; }
+ uint height() const { return _height; }
+};
- uint16 lines = 0;
- uint16 w = 0;
- *width = 0;
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
+class StringWriter_BR : public WrappedLineFormatter {
- char token[MAX_TOKEN_LEN];
+ uint _width, _height;
+ byte _color;
+ uint _x, _y;
- while (strlen(text) != 0) {
+ Graphics::Surface *_surf;
- text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
- tokenWidth = font->getStringWidth(token);
+protected:
+ StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font) {
- w += tokenWidth;
+ }
- if (!scumm_stricmp(token, "%p")) {
- lines++;
- } else {
- if (w > maxwidth) {
- w -= tokenWidth;
- lines++;
- if (w > *width)
- *width = w;
+ virtual void setup() {
+ }
- w = tokenWidth;
- }
+ virtual void action() {
+ if (_line.empty()) {
+ return;
}
+ uint16 rx = _x + (_surf->w - _lineWidth) / 2;
+ uint16 ry = _y + _lines * _font->height(); // y
- w += blankWidth;
- text = Common::ltrim(text);
+ byte *dst = (byte*)_surf->getBasePtr(rx, ry);
+ _font->setColor(_color);
+ _font->drawString(dst, _surf->w, _line.c_str());
}
- if (*width < w) *width = w;
- *width += 10;
-
- *height = lines * 10 + 20;
+ virtual void end() {
+ action();
+ }
- return;
-}
+public:
+ StringWriter_BR(Font *font) : WrappedLineFormatter(font) { }
+
+ void write(const char *text, uint maxWidth, byte color, Graphics::Surface *surf) {
+ StringExtent_BR se(_font);
+ se.calc(text, maxWidth);
+ _width = se.width() + 10;
+ _height = se.height() + 12;
+ _color = color;
+ _surf = surf;
+
+ _x = 0;
+ _y = (_surf->h - _height) / 2;
+ calc(text, maxWidth);
+ }
+};
class BalloonManager_br : public BalloonManager {
+ byte _textColors[2];
+
struct Balloon {
Common::Rect box;
Graphics::Surface *surface;
@@ -366,29 +553,12 @@ class BalloonManager_br : public BalloonManager {
Frames *_rightBalloon;
void cacheAnims();
- void getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height);
void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
- int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
+ int createBalloon(int16 w, int16 h, uint16 borderThickness);
Balloon *getBalloon(uint id);
Graphics::Surface *expandBalloon(Frames *data, int frameNum);
- void textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color);
- void textEmitCenteredLine();
- void textAccum(const Common::String &token, uint16 width);
- void textNewLine();
-
- Common::String _textLine;
- Graphics::Surface *_textSurf;
- Font *_textFont;
- uint16 _textX, _textY;
- byte _textColor;
- uint16 _textLines, _textWidth;
-
- void extentSetup(Font *font, int16 *width, int16 *height);
- void extentAction();
-
- int16 *_extentWidth, *_extentHeight;
-
+ StringWriter_BR _writer;
public:
BalloonManager_br(Disk *disk, Gfx *gfx);
@@ -396,9 +566,9 @@ public:
void freeBalloons();
int setLocationBalloon(char *text, bool endGame);
- int setDialogueBalloon(char *text, uint16 winding, byte textColor);
- int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
- void setBalloonText(uint id, char *text, byte textColor);
+ int setDialogueBalloon(char *text, uint16 winding, TextColor textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor);
+ void setBalloonText(uint id, char *text, TextColor textColor);
int hitTestDialogueBalloon(int x, int y);
};
@@ -419,12 +589,12 @@ Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum)
Graphics::Surface *surf = new Graphics::Surface;
surf->create(rect.width(), rect.height(), 1);
- _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR);
+ _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, LAYER_FOREGROUND, 100, BALLOON_TRANSPARENT_COLOR_BR);
return surf;
}
-int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) {
cacheAnims();
int id = _numBalloons;
@@ -447,7 +617,7 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
balloon->surface = expandBalloon(src, srcFrame);
src->getRect(srcFrame, balloon->box);
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ _writer.write(text, 216, _textColors[textColor], balloon->surface);
// TODO: extract some text to make a name for obj
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
@@ -455,14 +625,12 @@ int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 w
balloon->obj->y = y + balloon->box.top;
balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
- printf("balloon (%i, %i)\n", balloon->obj->x, balloon->obj->y);
-
_numBalloons++;
return id;
}
-int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, TextColor textColor) {
cacheAnims();
int id = _numBalloons;
@@ -473,11 +641,11 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC
if (winding == 0) {
src = _rightBalloon;
- srcFrame = id;
+ srcFrame = 0;
} else
if (winding == 1) {
src = _leftBalloon;
- srcFrame = 0;
+ srcFrame = id;
}
assert(src);
@@ -485,7 +653,7 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC
balloon->surface = expandBalloon(src, srcFrame);
src->getRect(srcFrame, balloon->box);
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+ _writer.write(text, 216, _textColors[textColor], balloon->surface);
// TODO: extract some text to make a name for obj
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
@@ -493,32 +661,51 @@ int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textC
balloon->obj->y = balloon->box.top;
balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
- if (id > 0) {
- balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height();
- }
-
_numBalloons++;
return id;
}
-void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { }
+void BalloonManager_br::setBalloonText(uint id, char *text, TextColor textColor) {
+ Balloon *balloon = getBalloon(id);
+
+ StringWriter_BR sw(_vm->_dialogueFont);
+ sw.write(text, 216, _textColors[textColor], balloon->surface);
+}
+
+int BalloonManager_br::createBalloon(int16 w, int16 h, uint16 borderThickness) {
+ assert(_numBalloons < 5);
+
+ int id = _numBalloons;
+ Balloon *balloon = &_intBalloons[id];
+
+ balloon->surface = new Graphics::Surface;
+ balloon->surface->create(w, h, 1);
+
+ Common::Rect rect(w, h);
+ balloon->surface->fillRect(rect, 1);
+ rect.grow(-borderThickness);
+ balloon->surface->fillRect(rect, 15);
+
+ _numBalloons++;
+
+ return id;
+}
int BalloonManager_br::setLocationBalloon(char *text, bool endGame) {
-/*
- int16 w, h;
+ StringExtent_BR se(_vm->_dialogueFont);
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+ se.calc(text, 240);
- int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR);
+ int id = createBalloon(se.width() + 20, se.height() + 30, 2);
Balloon *balloon = &_intBalloons[id];
- drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
- // TODO: extract some text to make a name for obj
+ _writer.write(text, 240, kNormalColor, balloon->surface);
+
balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
balloon->obj->x = 5;
balloon->obj->y = 5;
-*/
+
return 0;
}
@@ -527,11 +714,9 @@ int BalloonManager_br::hitTestDialogueBalloon(int x, int y) {
Common::Point p;
for (uint i = 0; i < _numBalloons; i++) {
- p.x = x - _intBalloons[i].obj->x;
- p.y = y - _intBalloons[i].obj->y;
-
- if (_intBalloons[i].box.contains(p))
+ if (_intBalloons[i].box.contains(x, y)) {
return i;
+ }
}
return -1;
@@ -556,155 +741,13 @@ void BalloonManager_br::cacheAnims() {
}
-void BalloonManager_br::extentSetup(Font *font, int16 *width, int16 *height) {
- _extentWidth = width;
- _extentHeight = height;
-
- _textLine.clear();
- _textLines = 0;
- _textWidth = 0;
- _textFont = font;
-}
-
-void BalloonManager_br::extentAction() {
- if (_textWidth > *_extentWidth) {
- *_extentWidth = _textWidth;
- }
- *_extentHeight = _textLines * _textFont->height();
-}
-
-void BalloonManager_br::textSetupRendering(const Common::String &text, Graphics::Surface *dest, Font *font, byte color) {
- uint16 maxWidth = 216;
-
- int16 w, h;
- getStringExtent(font, text.c_str(), maxWidth, &w, &h);
-
- w += 10;
- h += 12;
-
- _textLine.clear();
- _textSurf = dest;
- _textFont = font;
- _textX = 0;
- _textY = (_textSurf->h - h) / 2;
- _textColor = color;
- _textLines = 0;
- _textWidth = 0;
-}
-
-void BalloonManager_br::textEmitCenteredLine() {
- if (_textLine.empty()) {
- return;
- }
- uint16 rx = _textX + (_textSurf->w - _textWidth) / 2;
- uint16 ry = _textY + _textLines * _textFont->height(); // y
- _gfx->drawText(_textFont, _textSurf, rx, ry, _textLine.c_str(), _textColor);
-}
-
-void BalloonManager_br::textAccum(const Common::String &token, uint16 width) {
- if (token.empty()) {
- return;
- }
-
- _textWidth += width;
- _textLine += token;
-}
-
-void BalloonManager_br::textNewLine() {
- _textLines++;
- _textWidth = 0;
- _textLine.clear();
-}
-
-
-// TODO: really, base this and getStringExtent on some kind of LineTokenizer, instead of
-// repeating the algorithm and changing a couple of lines.
-void BalloonManager_br::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapWidth) {
- textSetupRendering(text, surf, font, color);
-
- wrapWidth = 216;
-
- Common::StringTokenizer tokenizer(text, " ");
- Common::String token;
- Common::String blank(" ");
-
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
-
- while (!tokenizer.empty()) {
- token = tokenizer.nextToken();
-
- if (token == '/') {
- tokenWidth = 0;
- textEmitCenteredLine();
- textNewLine();
- } else {
- // todo: expand '%'
- tokenWidth = font->getStringWidth(token.c_str());
-
- if (_textWidth == 0) {
- textAccum(token, tokenWidth);
- } else {
- if (_textWidth + blankWidth + tokenWidth <= wrapWidth) {
- textAccum(blank, blankWidth);
- textAccum(token, tokenWidth);
- } else {
- textEmitCenteredLine();
- textNewLine();
- textAccum(token, tokenWidth);
- }
- }
- }
- }
-
- textEmitCenteredLine();
-}
-
-
-
-void BalloonManager_br::getStringExtent(Font *font, const char *text, uint16 maxwidth, int16* width, int16* height) {
- extentSetup(font, width, height);
-
- Common::StringTokenizer tokenizer(text, " ");
- Common::String token;
- Common::String blank(" ");
-
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
-
- while (!tokenizer.empty()) {
- token = tokenizer.nextToken();
-
- if (token == '/') {
- tokenWidth = 0;
- extentAction();
- textNewLine();
- } else {
- // todo: expand '%'
- tokenWidth = font->getStringWidth(token.c_str());
-
- if (_textWidth == 0) {
- textAccum(token, tokenWidth);
- } else {
- if (_textWidth + blankWidth + tokenWidth <= maxwidth) {
- textAccum(blank, blankWidth);
- textAccum(token, tokenWidth);
- } else {
- extentAction();
- textNewLine();
- textAccum(token, tokenWidth);
- }
- }
- }
- }
-
- extentAction();
-}
-
-
+BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx),
+ _leftBalloon(0), _rightBalloon(0), _writer(_vm->_dialogueFont) {
-BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) {
+ _textColors[kSelectedColor] = 12;
+ _textColors[kUnselectedColor] = 0;
+ _textColors[kNormalColor] = 0;
}
BalloonManager_br::~BalloonManager_br() {
diff --git a/engines/parallaction/callables_br.cpp b/engines/parallaction/callables_br.cpp
index 628ba0c1f1..a4aec8e93e 100644
--- a/engines/parallaction/callables_br.cpp
+++ b/engines/parallaction/callables_br.cpp
@@ -41,7 +41,7 @@ void Parallaction_br::_c_ferrcycle(void*) {
}
void Parallaction_br::_c_lipsinc(void*) {
- warning("Parallaction_br::_c_lipsinc() not yet implemented");
+ warning("Unexpected lipsinc routine call! Please notify the team!");
}
void Parallaction_br::_c_albcycle(void*) {
diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp
index 9cd6b610ff..7915daa0b8 100644
--- a/engines/parallaction/callables_ns.cpp
+++ b/engines/parallaction/callables_ns.cpp
@@ -32,6 +32,7 @@
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
@@ -170,7 +171,7 @@ void Parallaction_ns::_c_fade(void *parm) {
_gfx->setPalette(pal);
_gfx->updateScreen();
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
}
return;
@@ -211,21 +212,17 @@ void Parallaction_ns::_c_moveSarc(void *parm) {
}
}
- _introSarcData1 = _introSarcData3 - _moveSarcZone1->_left;
- a->_z = _introSarcData3;
- a->_frame = _moveSarcZone1->_top - (_introSarcData1 / 20);
- _introSarcData3 = _moveSarcZone1->_left;
+ _introSarcData1 = _introSarcData3 - _moveSarcZone1->getX();
+ a->setZ(_introSarcData3);
+ a->setF(_moveSarcZone1->getY() - (_introSarcData1 / 20));
+ _introSarcData3 = _moveSarcZone1->getX();
if (_introSarcData1 > 0) {
- a->_left = _introSarcData1 / 2;
+ a->setX(_introSarcData1 / 2);
+ a->setY(2);
} else {
- a->_left = -_introSarcData1 / 2;
- }
-
- if (_introSarcData1 > 0) {
- a->_top = 2;
- } else {
- a->_top = -2;
+ a->setX(-_introSarcData1 / 2);
+ a->setY(-2);
}
return;
@@ -236,11 +233,11 @@ void Parallaction_ns::_c_moveSarc(void *parm) {
_moveSarcZone1->translate(_introSarcData1, -_introSarcData1 / 20);
_moveSarcZone0->translate(_introSarcData1, -_introSarcData1 / 20);
- if (_moveSarcZones[0]->_left == 35 &&
- _moveSarcZones[1]->_left == 68 &&
- _moveSarcZones[2]->_left == 101 &&
- _moveSarcZones[3]->_left == 134 &&
- _moveSarcZones[4]->_left == 167) {
+ if (_moveSarcZones[0]->getX() == 35 &&
+ _moveSarcZones[1]->getX() == 68 &&
+ _moveSarcZones[2]->getX() == 101 &&
+ _moveSarcZones[3]->getX() == 134 &&
+ _moveSarcZones[4]->getX() == 167) {
a = findAnimation("finito");
@@ -261,7 +258,7 @@ void Parallaction_ns::_c_contaFoglie(void *parm) {
if (num_foglie != 6)
return;
- _commandFlags |= 0x1000;
+ _globalFlags |= 0x1000;
return;
}
@@ -291,8 +288,8 @@ void Parallaction_ns::_c_onMouse(void *parm) {
void Parallaction_ns::_c_setMask(void *parm) {
- memset(_gfx->_backgroundInfo.mask.data + 3600, 0, 3600);
- _gfx->_backgroundInfo.layers[1] = 500;
+ memset(_gfx->_backgroundInfo->mask.data + 3600, 0, 3600);
+ _gfx->_backgroundInfo->layers[1] = 500;
return;
}
@@ -309,7 +306,7 @@ void Parallaction_ns::_c_endComment(void *param) {
_gfx->setPalette(_gfx->_palette);
_gfx->updateScreen();
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
}
_input->waitForButtonEvent(kMouseLeftUp);
@@ -328,10 +325,10 @@ void Parallaction_ns::_c_frankenstein(void *parm) {
}
for (uint16 _di = 0; _di < 30; _di++) {
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
_gfx->setPalette(pal0);
_gfx->updateScreen();
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
_gfx->setPalette(pal1);
_gfx->updateScreen();
}
@@ -345,7 +342,7 @@ void Parallaction_ns::_c_frankenstein(void *parm) {
void Parallaction_ns::_c_finito(void *parm) {
- setPartComplete(_char);
+ _saveLoad->setPartComplete(_char.getBaseName());
cleanInventory();
cleanupGame();
@@ -482,8 +479,8 @@ void Parallaction_ns::_c_sketch(void *parm) {
Graphics::drawLine(oldx, oldy, newx, newy, 0, zeroMask, &_gfx->_backgroundInfo);
- _rightHandAnim->_left = newx;
- _rightHandAnim->_top = newy - 20;
+ _rightHandAnim->setX(newx);
+ _rightHandAnim->setY(newy - 20);
index++;
@@ -496,17 +493,17 @@ void Parallaction_ns::_c_sketch(void *parm) {
void Parallaction_ns::_c_shade(void *parm) {
Common::Rect r(
- _rightHandAnim->_left - 36,
- _rightHandAnim->_top - 36,
- _rightHandAnim->_left,
- _rightHandAnim->_top
+ _rightHandAnim->getX() - 36,
+ _rightHandAnim->getY() - 36,
+ _rightHandAnim->getX(),
+ _rightHandAnim->getY()
);
- uint16 _di = r.left/4 + r.top * _gfx->_backgroundInfo.mask.internalWidth;
+ uint16 _di = r.left/4 + r.top * _gfx->_backgroundInfo->mask.internalWidth;
for (uint16 _si = r.top; _si < r.bottom; _si++) {
- memset(_gfx->_backgroundInfo.mask.data + _di, 0, r.width()/4+1);
- _di += _gfx->_backgroundInfo.mask.internalWidth;
+ memset(_gfx->_backgroundInfo->mask.data + _di, 0, r.width()/4+1);
+ _di += _gfx->_backgroundInfo->mask.internalWidth;
}
return;
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index f57976594e..0ff38913f7 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -101,14 +101,14 @@ bool Debugger::Cmd_Locations(int argc, const char **argv) {
bool Debugger::Cmd_GlobalFlags(int argc, const char **argv) {
- uint32 flags = _commandFlags;
+ uint32 flags = _globalFlags;
DebugPrintf("+------------------------------+---------+\n"
"| flag name | value |\n"
"+------------------------------+---------+\n");
- for (uint i = 0; i < _vm->_globalTable->count(); i++) {
+ for (uint i = 0; i < _vm->_globalFlagsNames->count(); i++) {
const char *value = ((flags & (1 << i)) == 0) ? "OFF" : "ON";
- DebugPrintf("|%-30s| %-6s|\n", _vm->_globalTable->item(i), value);
+ DebugPrintf("|%-30s| %-6s|\n", _vm->_globalFlagsNames->item(i), value);
}
DebugPrintf("+------------------------------+---------+\n");
@@ -157,7 +157,7 @@ bool Debugger::Cmd_Zones(int argc, const char **argv) {
"+--------------------+---+---+---+---+--------+--------+\n");
for ( ; b != e; b++) {
ZonePtr z = *b;
- DebugPrintf("|%-20s|%3i|%3i|%3i|%3i|%8x|%8x|\n", z->_name, z->_left, z->_top, z->_right, z->_bottom, z->_type, z->_flags );
+ DebugPrintf("|%-20s|%3i|%3i|%3i|%3i|%8x|%8x|\n", z->_name, z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height(), z->_type, z->_flags );
}
DebugPrintf("+--------------------+---+---+---+---+--------+--------+\n");
@@ -175,7 +175,7 @@ bool Debugger::Cmd_Animations(int argc, const char **argv) {
"+--------------------+---+---+---+---+--------+--------+\n");
for ( ; b != e; b++) {
AnimationPtr a = *b;
- DebugPrintf("|%-20s|%3i|%3i|%3i|%3i|%8x|%8x|\n", a->_name, a->_left, a->_top, a->_z, a->_frame, a->_type, a->_flags );
+ DebugPrintf("|%-20s|%3i|%3i|%3i|%3i|%8x|%8x|\n", a->_name, a->getX(), a->getY(), a->getZ(), a->getF(), a->_type, a->_flags );
}
DebugPrintf("+--------------------+---+---+---+---+--------+--------+\n");
@@ -187,19 +187,19 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) {
const char *objType[] = { "DOOR", "GET", "ANIM" };
- DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n"
- "| name | x | y | z | f | type | visi |\n"
- "+--------------------+-----+-----+-----+-----+--------+--------+\n");
+ DebugPrintf("+--------------------+-----+-----+-----+-------+-----+--------+--------+\n"
+ "| name | x | y | z | layer | f | type | visi |\n"
+ "+--------------------+-----+-----+-----+-------+-----+--------+--------+\n");
GfxObjList::iterator b = _vm->_gfx->_gfxobjList.begin();
GfxObjList::iterator e = _vm->_gfx->_gfxobjList.end();
for ( ; b != e; b++) {
GfxObj *obj = *b;
- DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], obj->isVisible() );
+ DebugPrintf("|%-20s|%5i|%5i|%5i|%7i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->layer, obj->frame, objType[obj->type], obj->isVisible() );
}
- DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n");
+ DebugPrintf("+--------------------+-----+-----+-----+-------+-----+--------+--------+\n");
return true;
}
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
index 0476b01454..d2444c642e 100644
--- a/engines/parallaction/detection.cpp
+++ b/engines/parallaction/detection.cpp
@@ -243,9 +243,20 @@ public:
return "Nippon Safes Inc. (C) Dynabyte";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
};
+bool ParallactionMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Parallaction::PARALLACTIONGameDescription *gd = (const Parallaction::PARALLACTIONGameDescription *)desc;
bool res = true;
@@ -265,6 +276,43 @@ bool ParallactionMetaEngine::createInstance(OSystem *syst, Engine **engine, cons
return res;
}
+SaveStateList ParallactionMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ Common::String pattern = target;
+ pattern += ".0??";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 2 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ Common::String saveDesc = in->readLine();
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void ParallactionMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".0%02d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
#if PLUGIN_ENABLED_DYNAMIC(PARALLACTION)
REGISTER_PLUGIN_DYNAMIC(PARALLACTION, PLUGIN_TYPE_ENGINE, ParallactionMetaEngine);
#else
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 21584a0525..a2de3cbbf3 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -168,12 +168,12 @@ bool DialogueManager::displayAnswer(uint16 i) {
uint32 flags = _vm->getLocationFlags();
if (a->_yesFlags & kFlagsGlobal)
- flags = _commandFlags | kFlagsGlobal;
+ flags = _globalFlags | kFlagsGlobal;
// display suitable answers
if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) {
- int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3);
+ int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, BalloonManager::kUnselectedColor);
assert(id >= 0);
_visAnswers[id] = i;
@@ -203,7 +203,7 @@ bool DialogueManager::displayAnswers() {
if (_numVisAnswers == 1) {
int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y);
_vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF);
- _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, 0);
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[_visAnswers[0]]->_text, BalloonManager::kNormalColor);
} else
if (_numVisAnswers > 1) {
int id = _vm->_gfx->setItem(_answerer, _ballonPos._answerChar.x, _ballonPos._answerChar.y);
@@ -218,7 +218,7 @@ bool DialogueManager::displayAnswers() {
bool DialogueManager::displayQuestion() {
if (!scumm_stricmp(_q->_text, "NULL")) return false;
- _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, 0);
+ _vm->_balloonMan->setSingleBalloon(_q->_text, _ballonPos._questionBalloon.x, _ballonPos._questionBalloon.y, _q->_mood & 0x10, BalloonManager::kNormalColor);
int id = _vm->_gfx->setItem(_questioner, _ballonPos._questionChar.x, _ballonPos._questionChar.y);
_vm->_gfx->setItemFrame(id, _q->_mood & 0xF);
@@ -256,7 +256,7 @@ int16 DialogueManager::askPassword() {
}
if (_passwordChanged) {
- _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3);
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, BalloonManager::kNormalColor);
_passwordChanged = false;
}
@@ -286,11 +286,11 @@ int16 DialogueManager::selectAnswerN() {
if (_selection != _oldSelection) {
if (_oldSelection != -1) {
- _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, 3);
+ _vm->_balloonMan->setBalloonText(_oldSelection, _q->_answers[_visAnswers[_oldSelection]]->_text, BalloonManager::kUnselectedColor);
}
if (_selection != -1) {
- _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, 0);
+ _vm->_balloonMan->setBalloonText(_selection, _q->_answers[_visAnswers[_selection]]->_text, BalloonManager::kSelectedColor);
_vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[_selection]]->_mood & 0xF);
}
}
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index ee393afd6a..30d820c6d2 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -29,10 +29,12 @@
#define PATH_LEN 200
#include "common/fs.h"
-
#include "common/file.h"
+
#include "graphics/surface.h"
+#include "parallaction/graphics.h"
+
namespace Parallaction {
class Table;
@@ -69,6 +71,7 @@ public:
virtual Table* loadTable(const char* name) = 0;
virtual Common::SeekableReadStream* loadMusic(const char* name) = 0;
virtual Common::ReadStream* loadSound(const char* name) = 0;
+ virtual void loadMask(const char *name, MaskBuffer &buffer) { }
};
@@ -101,10 +104,10 @@ public:
Common::String name() const;
bool openArchivedFile(const char *name);
void closeArchivedFile();
- uint32 size() const;
- uint32 pos() const;
+ int32 size() const;
+ int32 pos() const;
bool eos() const;
- void seek(int32 offs, int whence = SEEK_SET);
+ bool seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *dataPtr, uint32 dataSize);
};
@@ -208,21 +211,21 @@ protected:
Parallaction *_vm;
- FilesystemNode _baseDir;
- FilesystemNode _partDir;
+ Common::FilesystemNode _baseDir;
+ Common::FilesystemNode _partDir;
- FilesystemNode _aniDir;
- FilesystemNode _bkgDir;
- FilesystemNode _mscDir;
- FilesystemNode _mskDir;
- FilesystemNode _pthDir;
- FilesystemNode _rasDir;
- FilesystemNode _scrDir;
- FilesystemNode _sfxDir;
- FilesystemNode _talDir;
+ Common::FilesystemNode _aniDir;
+ Common::FilesystemNode _bkgDir;
+ Common::FilesystemNode _mscDir;
+ Common::FilesystemNode _mskDir;
+ Common::FilesystemNode _pthDir;
+ Common::FilesystemNode _rasDir;
+ Common::FilesystemNode _scrDir;
+ Common::FilesystemNode _sfxDir;
+ Common::FilesystemNode _talDir;
protected:
- void errorFileNotFound(const FilesystemNode &dir, const Common::String &filename);
+ void errorFileNotFound(const Common::FilesystemNode &dir, const Common::String &filename);
Font *createFont(const char *name, Common::ReadStream &stream);
Sprites* createSprites(Common::ReadStream &stream);
void loadBitmap(Common::SeekableReadStream &stream, Graphics::Surface &surf, byte *palette);
@@ -248,6 +251,7 @@ public:
Table* loadTable(const char* name);
Common::SeekableReadStream* loadMusic(const char* name);
Common::ReadStream* loadSound(const char* name);
+ void loadMask(const char *name, MaskBuffer &buffer);
};
class DosDemo_br : public DosDisk_br {
@@ -267,17 +271,16 @@ protected:
Sprites* createSprites(Common::ReadStream &stream);
Font *createFont(const char *name, Common::SeekableReadStream &stream);
- void loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream);
void loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream);
- FilesystemNode _baseBkgDir;
- FilesystemNode _fntDir;
- FilesystemNode _commonAniDir;
- FilesystemNode _commonBkgDir;
- FilesystemNode _commonMscDir;
- FilesystemNode _commonMskDir;
- FilesystemNode _commonPthDir;
- FilesystemNode _commonTalDir;
+ Common::FilesystemNode _baseBkgDir;
+ Common::FilesystemNode _fntDir;
+ Common::FilesystemNode _commonAniDir;
+ Common::FilesystemNode _commonBkgDir;
+ Common::FilesystemNode _commonMscDir;
+ Common::FilesystemNode _commonMskDir;
+ Common::FilesystemNode _commonPthDir;
+ Common::FilesystemNode _commonTalDir;
public:
AmigaDisk_br(Parallaction *vm);
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 2285c5608e..24893b7b05 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -91,7 +91,7 @@ struct Sprites : public Frames {
-void DosDisk_br::errorFileNotFound(const FilesystemNode &dir, const Common::String &filename) {
+void DosDisk_br::errorFileNotFound(const Common::FilesystemNode &dir, const Common::String &filename) {
error("File '%s' not found in directory '%s'", filename.c_str(), dir.getDisplayName().c_str());
}
@@ -134,7 +134,7 @@ GfxObj* DosDisk_br::loadTalk(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name);
Common::String path(name);
- FilesystemNode node = _talDir.getChild(path);
+ Common::FilesystemNode node = _talDir.getChild(path);
if (!node.exists()) {
path += ".tal";
node = _talDir.getChild(path);
@@ -160,11 +160,11 @@ Script* DosDisk_br::loadLocation(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadLocation");
Common::String langs[4] = { "it", "fr", "en", "ge" };
- FilesystemNode locDir = _partDir.getChild(langs[_language]);
+ Common::FilesystemNode locDir = _partDir.getChild(langs[_language]);
Common::String path(name);
path += ".slf";
- FilesystemNode node = locDir.getChild(path);
+ Common::FilesystemNode node = locDir.getChild(path);
if (!node.exists()) {
path = Common::String(name) + ".loc";
node = locDir.getChild(path);
@@ -183,7 +183,7 @@ Script* DosDisk_br::loadScript(const char* name) {
Common::String path(name);
path += ".scr";
- FilesystemNode node = _scrDir.getChild(path);
+ Common::FilesystemNode node = _scrDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_scrDir, path);
}
@@ -221,7 +221,7 @@ Frames* DosDisk_br::loadPointer(const char *name) {
Common::String path(name);
path += ".ras";
- FilesystemNode node = _baseDir.getChild(path);
+ Common::FilesystemNode node = _baseDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_baseDir, path);
}
@@ -240,7 +240,7 @@ Font* DosDisk_br::loadFont(const char* name) {
Common::String path(name);
path += ".fnt";
- FilesystemNode node = _baseDir.getChild(path);
+ Common::FilesystemNode node = _baseDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_baseDir, path);
}
@@ -255,7 +255,7 @@ GfxObj* DosDisk_br::loadObjects(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadObjects");
Common::String path(name);
- FilesystemNode node = _partDir.getChild(path);
+ Common::FilesystemNode node = _partDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_partDir, path);
}
@@ -274,7 +274,7 @@ GfxObj* DosDisk_br::loadStatic(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadStatic");
Common::String path(name);
- FilesystemNode node = _rasDir.getChild(path);
+ Common::FilesystemNode node = _rasDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_rasDir, path);
}
@@ -312,7 +312,7 @@ Frames* DosDisk_br::loadFrames(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadFrames");
Common::String path(name);
- FilesystemNode node = _aniDir.getChild(path);
+ Common::FilesystemNode node = _aniDir.getChild(path);
if (!node.exists()) {
path += ".ani";
node = _aniDir.getChild(path);
@@ -336,7 +336,7 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
Common::String path(name);
path += ".bmp";
- FilesystemNode node = _baseDir.getChild(path);
+ Common::FilesystemNode node = _baseDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_baseDir, path);
}
@@ -357,11 +357,34 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
return;
}
+void DosDisk_br::loadMask(const char *name, MaskBuffer &buffer) {
+ if (!name) {
+ return;
+ }
+
+ Common::String filepath;
+ Common::FilesystemNode node;
+ Common::File stream;
+
+ filepath = Common::String(name) + ".msk";
+ node = _mskDir.getChild(filepath);
+ if (!node.exists()) {
+ errorFileNotFound(_mskDir, filepath);
+ }
+ stream.open(node);
+
+ // NOTE: info.width and info.height are only valid if the background graphics
+ // have already been loaded
+ buffer.bigEndian = false;
+ stream.read(buffer.data, buffer.size);
+ stream.close();
+}
+
void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) {
debugC(5, kDebugDisk, "DosDisk_br::loadScenery");
Common::String filepath;
- FilesystemNode node;
+ Common::FilesystemNode node;
Common::File stream;
if (name) {
@@ -424,7 +447,7 @@ Table* DosDisk_br::loadTable(const char* name) {
Common::String path(name);
path += ".tab";
- FilesystemNode node = _partDir.getChild(path);
+ Common::FilesystemNode node = _partDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_partDir, path);
}
@@ -495,7 +518,7 @@ AmigaDisk_br::AmigaDisk_br(Parallaction *vm) : DosDisk_br(vm) {
_baseBkgDir = _baseDir.getChild("backs");
- FilesystemNode commonDir = _baseDir.getChild("common");
+ Common::FilesystemNode commonDir = _baseDir.getChild("common");
_commonAniDir = commonDir.getChild("anims");
_commonBkgDir = commonDir.getChild("backs");
_commonMscDir = commonDir.getChild("msc");
@@ -510,33 +533,6 @@ AmigaDisk_br::~AmigaDisk_br() {
}
-/*
- FIXME: mask values are not computed correctly for level 1 and 2
-
- NOTE: this routine is only able to build masks for Nippon Safes, since mask widths are hardcoded
- into the main loop.
-*/
-void buildMask2(byte* buf) {
-
- byte mask1[16] = { 0, 0x80, 0x20, 0xA0, 8, 0x88, 0x28, 0xA8, 2, 0x82, 0x22, 0xA2, 0xA, 0x8A, 0x2A, 0xAA };
- byte mask0[16] = { 0, 0x40, 0x10, 0x50, 4, 0x44, 0x14, 0x54, 1, 0x41, 0x11, 0x51, 0x5, 0x45, 0x15, 0x55 };
-
- byte plane0[40];
- byte plane1[40];
-
- for (int32 i = 0; i < _vm->_screenHeight; i++) {
-
- memcpy(plane0, buf, 40);
- memcpy(plane1, buf+40, 40);
-
- for (uint32 j = 0; j < 40; j++) {
- *buf++ = mask0[(plane0[j] & 0xF0) >> 4] | mask1[(plane1[j] & 0xF0) >> 4];
- *buf++ = mask0[plane0[j] & 0xF] | mask1[plane1[j] & 0xF];
- }
-
- }
-}
-
void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStream &stream) {
byte *pal;
@@ -565,33 +561,12 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, Common::SeekableReadStre
return;
}
-void AmigaDisk_br::loadMask(BackgroundInfo& info, Common::SeekableReadStream &stream) {
- stream.seek(0x30, SEEK_SET);
-
- byte r, g, b;
- for (uint i = 0; i < 4; i++) {
- r = stream.readByte();
- g = stream.readByte();
- b = stream.readByte();
-
- info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF;
- }
-
- stream.seek(0x126, SEEK_SET); // HACK: skipping IFF/ILBM header should be done by analysis, not magic
- Graphics::PackBitsReadStream unpackedStream(stream);
-
- info.mask.create(info.width, info.height);
- unpackedStream.read(info.mask.data, info.mask.size);
- buildMask2(info.mask.data);
-
- return;
-}
void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery '%s', '%s' '%s'", name, mask, path);
Common::String filepath;
- FilesystemNode node;
+ Common::FilesystemNode node;
Common::File stream;
if (name) {
@@ -608,7 +583,7 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha
loadBackground(info, stream);
stream.close();
}
-
+#if 0
if (mask && _mskDir.exists()) {
filepath = Common::String(mask) + ".msk";
node = _mskDir.getChild(filepath);
@@ -619,11 +594,16 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha
if (node.exists()) {
stream.open(node);
+ stream.seek(0x30, SEEK_SET);
+ Graphics::PackBitsReadStream unpackedStream(stream);
+ info.mask.create(info.width, info.height);
+ unpackedStream.read(info.mask.data, info.mask.size);
+ // TODO: there is another step to do after decompression...
loadMask(info, stream);
stream.close();
}
}
-
+#endif
if (path && _pthDir.exists()) {
filepath = Common::String(path) + ".pth";
node = _pthDir.getChild(filepath);
@@ -650,7 +630,7 @@ void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
Common::String path(name);
path += ".bkg";
- FilesystemNode node = _baseBkgDir.getChild(path);
+ Common::FilesystemNode node = _baseBkgDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_baseBkgDir, path);
}
@@ -664,7 +644,7 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
Common::String path(name);
- FilesystemNode node = _rasDir.getChild(path);
+ Common::FilesystemNode node = _rasDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_rasDir, path);
}
@@ -707,7 +687,7 @@ Frames* AmigaDisk_br::loadFrames(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadFrames '%s'", name);
Common::String path(name);
- FilesystemNode node = _aniDir.getChild(path);
+ Common::FilesystemNode node = _aniDir.getChild(path);
if (!node.exists()) {
path += ".ani";
node = _aniDir.getChild(path);
@@ -733,7 +713,7 @@ GfxObj* AmigaDisk_br::loadTalk(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name);
Common::String path(name);
- FilesystemNode node = _talDir.getChild(path);
+ Common::FilesystemNode node = _talDir.getChild(path);
if (!node.exists()) {
path += ".tal";
node = _talDir.getChild(path);
@@ -760,7 +740,7 @@ Font* AmigaDisk_br::loadFont(const char* name) {
Common::String path(name);
path += ".font";
- FilesystemNode node = _fntDir.getChild(path);
+ Common::FilesystemNode node = _fntDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_fntDir, path);
}
@@ -776,8 +756,6 @@ Font* AmigaDisk_br::loadFont(const char* name) {
while ((ch = stream.readByte()) != 0) fontFile += ch;
stream.close();
- printf("fontDir = %s, fontFile = %s\n", fontDir.c_str(), fontFile.c_str());
-
node = _fntDir.getChild(fontDir);
if (!node.exists()) {
errorFileNotFound(_fntDir, fontDir);
@@ -795,7 +773,7 @@ Common::SeekableReadStream* AmigaDisk_br::loadMusic(const char* name) {
debugC(5, kDebugDisk, "AmigaDisk_br::loadMusic");
Common::String path(name);
- FilesystemNode node = _mscDir.getChild(path);
+ Common::FilesystemNode node = _mscDir.getChild(path);
if (!node.exists()) {
// TODO (Kirben): error out when music file is not found?
return 0;
@@ -811,7 +789,7 @@ Common::ReadStream* AmigaDisk_br::loadSound(const char* name) {
debugC(5, kDebugDisk, "AmigaDisk_br::loadSound");
Common::String path(name);
- FilesystemNode node = _sfxDir.getChild(path);
+ Common::FilesystemNode node = _sfxDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_sfxDir, path);
}
@@ -825,7 +803,7 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name) {
debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects");
Common::String path(name);
- FilesystemNode node = _partDir.getChild(path);
+ Common::FilesystemNode node = _partDir.getChild(path);
if (!node.exists()) {
errorFileNotFound(_partDir, path);
}
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 55e6fc5e77..54d4d1e5da 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -156,19 +156,19 @@ void Archive::closeArchivedFile() {
}
-uint32 Archive::size() const {
+int32 Archive::size() const {
return (_file == true ? _fileEndOffset - _fileOffset : 0);
}
-uint32 Archive::pos() const {
+int32 Archive::pos() const {
return (_file == true ? _fileCursor - _fileOffset : 0 );
}
bool Archive::eos() const {
- return (_file == true ? _fileCursor == _fileEndOffset : true );
+ return (_file == true ? _fileCursor == _fileEndOffset : true ); // FIXME (eos definition change)
}
-void Archive::seek(int32 offs, int whence) {
+bool Archive::seek(int32 offs, int whence) {
assert(_file == true && _fileCursor <= _fileEndOffset);
switch (whence) {
@@ -184,7 +184,7 @@ void Archive::seek(int32 offs, int whence) {
}
assert(_fileCursor <= _fileEndOffset && _fileCursor >= _fileOffset);
- _archive.seek(_fileCursor, SEEK_SET);
+ return _archive.seek(_fileCursor, SEEK_SET);
}
uint32 Archive::read(void *dataPtr, uint32 dataSize) {
@@ -234,16 +234,16 @@ public:
return _input->read(data, dataSize);
}
- uint32 pos() const {
+ int32 pos() const {
return _input->pos();
}
- uint32 size() const {
+ int32 size() const {
return _input->size();
}
- void seek(int32 offset, int whence) {
- _input->seek(offset, whence);
+ bool seek(int32 offset, int whence) {
+ return _input->seek(offset, whence);
}
};
@@ -798,11 +798,11 @@ public:
if (_dispose) delete _stream;
}
- uint32 size() const {
+ int32 size() const {
return _stream->size();
}
- uint32 pos() const {
+ int32 pos() const {
return _stream->pos();
}
@@ -810,8 +810,8 @@ public:
return _stream->eos();
}
- void seek(int32 offs, int whence = SEEK_SET) {
- _stream->seek(offs, whence);
+ bool seek(int32 offs, int whence = SEEK_SET) {
+ return _stream->seek(offs, whence);
}
uint32 read(void *dataPtr, uint32 dataSize) {
diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h
index 22e75744f1..4239857ec0 100644
--- a/engines/parallaction/exec.h
+++ b/engines/parallaction/exec.h
@@ -84,8 +84,6 @@ class CommandExec_ns : public CommandExec {
Parallaction_ns *_vm;
protected:
- void updateGetZone(ZonePtr z, bool visible);
-
DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid);
DECLARE_UNQUALIFIED_COMMAND_OPCODE(set);
DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear);
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 0b7400f0f7..bcc4a5b532 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -97,8 +97,9 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
} else {
_subtitle[1] = -1;
}
-
+#if 0 // disabled because no references to lip sync has been found in the scripts
_subtitleLipSync = 0;
+#endif
}
void Parallaction_br::clearSubtitles() {
@@ -122,48 +123,23 @@ DECLARE_COMMAND_OPCODE(location) {
DECLARE_COMMAND_OPCODE(open) {
warning("Parallaction_br::cmdOp_open command not yet implemented");
- _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed;
- if (_ctxt.cmd->u._zone->u.door->gfxobj) {
- _vm->updateDoor(_ctxt.cmd->u._zone);
- }
+ _vm->updateDoor(_ctxt.cmd->u._zone, false);
}
DECLARE_COMMAND_OPCODE(close) {
warning("Parallaction_br::cmdOp_close not yet implemented");
- _ctxt.cmd->u._zone->_flags |= kFlagsClosed;
- if (_ctxt.cmd->u._zone->u.door->gfxobj) {
- _vm->updateDoor(_ctxt.cmd->u._zone);
- }
+ _vm->updateDoor(_ctxt.cmd->u._zone, true);
}
DECLARE_COMMAND_OPCODE(on) {
- CommandData *data = &_ctxt.cmd->u;
- ZonePtr z = data->_zone;
-
- if (z) {
- z->_flags |= kFlagsActive;
- z->_flags &= ~kFlagsRemove;
-
- if ((z->_type & 0xFFFF) & kZoneGet) {
- _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
- }
- }
+ _vm->showZone(_ctxt.cmd->u._zone, true);
}
DECLARE_COMMAND_OPCODE(off) {
- CommandData *data = &_ctxt.cmd->u;
- ZonePtr z = data->_zone;
-
- if (z) {
- z->_flags |= kFlagsRemove;
-
- if ((z->_type & 0xFFFF) & kZoneGet) {
- _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
- }
- }
+ _vm->showZone(_ctxt.cmd->u._zone, false);
}
@@ -335,42 +311,18 @@ DECLARE_COMMAND_OPCODE(offsave) {
DECLARE_INSTRUCTION_OPCODE(on) {
- InstructionPtr inst = *_ctxt.inst;
- ZonePtr z = inst->_z;
-
- if (z) {
- z->_flags |= kFlagsActive;
- z->_flags &= ~kFlagsRemove;
-
- if ((z->_type & 0xFFFF) & kZoneGet) {
- _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
- }
- }
+ _vm->showZone((*_ctxt.inst)->_z, true);
}
DECLARE_INSTRUCTION_OPCODE(off) {
- InstructionPtr inst = *_ctxt.inst;
- ZonePtr z = inst->_z;
-
- if (z) {
- z->_flags |= kFlagsRemove;
-
- if ((z->_type & 0xFFFF) & kZoneGet) {
- _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
- }
- }
+ _vm->showZone((*_ctxt.inst)->_z, false);
}
DECLARE_INSTRUCTION_OPCODE(set) {
InstructionPtr inst = *_ctxt.inst;
-
- int16 rvalue = inst->_opB.getRValue();
- int16* lvalue = inst->_opA.getLValue();
-
- *lvalue = rvalue;
-
+ inst->_opA.setValue(inst->_opB.getValue());
}
@@ -378,7 +330,7 @@ DECLARE_INSTRUCTION_OPCODE(set) {
DECLARE_INSTRUCTION_OPCODE(inc) {
InstructionPtr inst = *_ctxt.inst;
- int16 rvalue = inst->_opB.getRValue();
+ int16 rvalue = inst->_opB.getValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (rvalue > 0 ? rvalue : -rvalue);
@@ -387,32 +339,30 @@ DECLARE_INSTRUCTION_OPCODE(inc) {
rvalue = (rvalue > 0 ? 1 : -1);
}
- int16 *lvalue = inst->_opA.getLValue();
+ int16 lvalue = inst->_opA.getValue();
switch (inst->_index) {
case INST_INC:
- *lvalue += rvalue;
+ lvalue += rvalue;
break;
case INST_DEC:
- *lvalue -= rvalue;
+ lvalue -= rvalue;
break;
case INST_MUL:
- *lvalue *= rvalue;
+ lvalue *= rvalue;
break;
case INST_DIV:
- *lvalue /= rvalue;
+ lvalue /= rvalue;
break;
default:
error("This should never happen. Report immediately");
}
- if (inst->_opA._flags & kParaLocal) {
- inst->_opA._local->wrap();
- }
+ inst->_opA.setValue(lvalue);
}
@@ -445,11 +395,7 @@ DECLARE_INSTRUCTION_OPCODE(move) {
DECLARE_INSTRUCTION_OPCODE(color) {
InstructionPtr inst = *_ctxt.inst;
-
- int16 entry = inst->_opB.getRValue();
-
- _vm->_gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]);
-
+ _vm->_gfx->_palette.setEntry(inst->_opB.getValue(), inst->_colors[0], inst->_colors[1], inst->_colors[2]);
}
@@ -600,27 +546,4 @@ ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm
ProgramExec_br::~ProgramExec_br() {
}
-#if 0
-void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) {
-
-}
-
-void Parallaction_br::jobPauseSfx(void *parm, Job *job) {
-
-}
-
-
-void Parallaction_br::jobStopFollower(void *parm, Job *job) {
-
-}
-
-
-void Parallaction_br::jobScroll(void *parm, Job *job) {
-
-}
-#endif
-
-
-
-
} // namespace Parallaction
diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp
index 3e3ee19a03..2ce50f498e 100644
--- a/engines/parallaction/exec_ns.cpp
+++ b/engines/parallaction/exec_ns.cpp
@@ -80,7 +80,7 @@ DECLARE_INSTRUCTION_OPCODE(off) {
DECLARE_INSTRUCTION_OPCODE(loop) {
InstructionPtr inst = *_ctxt.inst;
- _ctxt.program->_loopCounter = inst->_opB.getRValue();
+ _ctxt.program->_loopCounter = inst->_opB.getValue();
_ctxt.program->_loopStart = _ctxt.ip;
}
@@ -93,7 +93,7 @@ DECLARE_INSTRUCTION_OPCODE(endloop) {
DECLARE_INSTRUCTION_OPCODE(inc) {
InstructionPtr inst = *_ctxt.inst;
- int16 _si = inst->_opB.getRValue();
+ int16 _si = inst->_opB.getValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (_si > 0 ? _si : -_si);
@@ -102,29 +102,22 @@ DECLARE_INSTRUCTION_OPCODE(inc) {
_si = (_si > 0 ? 1 : -1);
}
- int16* lvalue = inst->_opA.getLValue();
+ int16 lvalue = inst->_opA.getValue();
if (inst->_index == INST_INC) {
- *lvalue += _si;
+ lvalue += _si;
} else {
- *lvalue -= _si;
+ lvalue -= _si;
}
- if (inst->_opA._flags & kParaLocal) {
- inst->_opA._local->wrap();
- }
+ inst->_opA.setValue(lvalue);
}
DECLARE_INSTRUCTION_OPCODE(set) {
InstructionPtr inst = *_ctxt.inst;
-
- int16 _si = inst->_opB.getRValue();
- int16 *lvalue = inst->_opA.getLValue();
-
- *lvalue = _si;
-
+ inst->_opA.setValue(inst->_opB.getValue());
}
@@ -133,10 +126,10 @@ DECLARE_INSTRUCTION_OPCODE(put) {
Graphics::Surface v18;
v18.w = inst->_a->width();
v18.h = inst->_a->height();
- v18.pixels = inst->_a->getFrameData(inst->_a->_frame);
+ v18.pixels = inst->_a->getFrameData(inst->_a->getF());
- int16 x = inst->_opA.getRValue();
- int16 y = inst->_opB.getRValue();
+ int16 x = inst->_opA.getValue();
+ int16 y = inst->_opB.getValue();
bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut;
_vm->_gfx->patchBackground(v18, x, y, mask);
@@ -176,8 +169,8 @@ DECLARE_INSTRUCTION_OPCODE(sound) {
DECLARE_INSTRUCTION_OPCODE(move) {
InstructionPtr inst = (*_ctxt.inst);
- int16 x = inst->_opA.getRValue();
- int16 y = inst->_opB.getRValue();
+ int16 x = inst->_opA.getValue();
+ int16 y = inst->_opB.getValue();
_vm->_char.scheduleWalk(x, y);
}
@@ -203,7 +196,7 @@ DECLARE_COMMAND_OPCODE(invalid) {
DECLARE_COMMAND_OPCODE(set) {
if (_ctxt.cmd->u._flags & kFlagsGlobal) {
_ctxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags |= _ctxt.cmd->u._flags;
+ _globalFlags |= _ctxt.cmd->u._flags;
} else {
_vm->setLocationFlags(_ctxt.cmd->u._flags);
}
@@ -213,7 +206,7 @@ DECLARE_COMMAND_OPCODE(set) {
DECLARE_COMMAND_OPCODE(clear) {
if (_ctxt.cmd->u._flags & kFlagsGlobal) {
_ctxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags &= ~_ctxt.cmd->u._flags;
+ _globalFlags &= ~_ctxt.cmd->u._flags;
} else {
_vm->clearLocationFlags(_ctxt.cmd->u._flags);
}
@@ -246,48 +239,21 @@ DECLARE_COMMAND_OPCODE(location) {
DECLARE_COMMAND_OPCODE(open) {
- _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed;
- if (_ctxt.cmd->u._zone->u.door->gfxobj) {
- _vm->updateDoor(_ctxt.cmd->u._zone);
- }
+ _vm->updateDoor(_ctxt.cmd->u._zone, false);
}
DECLARE_COMMAND_OPCODE(close) {
- _ctxt.cmd->u._zone->_flags |= kFlagsClosed;
- if (_ctxt.cmd->u._zone->u.door->gfxobj) {
- _vm->updateDoor(_ctxt.cmd->u._zone);
- }
-}
-
-void CommandExec_ns::updateGetZone(ZonePtr z, bool visible) {
- if (!z) {
- return;
- }
-
- if ((z->_type & 0xFFFF) == kZoneGet) {
- _vm->_gfx->showGfxObj(z->u.get->gfxobj, visible);
- }
+ _vm->updateDoor(_ctxt.cmd->u._zone, true);
}
DECLARE_COMMAND_OPCODE(on) {
- ZonePtr z = _ctxt.cmd->u._zone;
-
- if (z) {
- z->_flags &= ~kFlagsRemove;
- z->_flags |= kFlagsActive;
- updateGetZone(z, true);
- }
+ _vm->showZone(_ctxt.cmd->u._zone, true);
}
DECLARE_COMMAND_OPCODE(off) {
- ZonePtr z = _ctxt.cmd->u._zone;
-
- if (z) {
- _ctxt.cmd->u._zone->_flags |= kFlagsRemove;
- updateGetZone(z, false);
- }
+ _vm->showZone(_ctxt.cmd->u._zone, false);
}
@@ -299,7 +265,7 @@ DECLARE_COMMAND_OPCODE(call) {
DECLARE_COMMAND_OPCODE(toggle) {
if (_ctxt.cmd->u._flags & kFlagsGlobal) {
_ctxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags ^= _ctxt.cmd->u._flags;
+ _globalFlags ^= _ctxt.cmd->u._flags;
} else {
_vm->toggleLocationFlags(_ctxt.cmd->u._flags);
}
@@ -312,7 +278,8 @@ DECLARE_COMMAND_OPCODE(drop){
DECLARE_COMMAND_OPCODE(quit) {
- _engineFlags |= kEngineQuit;
+ _vm->_quit = true;
+ _vm->quitGame();
}
@@ -326,58 +293,6 @@ DECLARE_COMMAND_OPCODE(stop) {
}
-void Parallaction_ns::drawAnimations() {
- debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n");
-
- uint16 layer = 0;
-
- for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) {
-
- AnimationPtr anim = *it;
- GfxObj *obj = anim->gfxobj;
-
- // Validation is performed here, so that every animation is affected, instead that only the ones
- // who *own* a script. In fact, some scripts can change values in other animations.
- // The right way to do this would be to enforce validation when any variable is modified from
- // a script.
- anim->validateScriptVars();
-
- if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) {
-
- if (anim->_flags & kFlagsNoMasked)
- layer = 3;
- else
- layer = _gfx->_backgroundInfo.getLayer(anim->_top + anim->height());
-
- if (obj) {
- _gfx->showGfxObj(obj, true);
- obj->frame = anim->_frame;
- obj->x = anim->_left;
- obj->y = anim->_top;
- obj->z = anim->_z;
- obj->layer = layer;
- }
- }
-
- if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) {
- anim->_flags &= ~kFlagsRemove;
- anim->_oldPos.x = -1000;
- }
-
- if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) {
- anim->_flags &= ~kFlagsActive;
- anim->_flags |= kFlagsRemove;
- if (obj) {
- _gfx->showGfxObj(obj, false);
- }
- }
- }
-
- debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n");
-
- return;
-}
-
void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) {
debugC(9, kDebugExec, "runScript(Animation = %s)", a->_name);
@@ -418,7 +333,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
AnimationPtr a = (*it)->_anim;
if (a->_flags & kFlagsCharacter)
- a->_z = a->_top + a->height();
+ a->setZ(a->getFrameY() + a->height());
if ((a->_flags & kFlagsActing) == 0)
continue;
@@ -426,7 +341,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
runScript(*it, a);
if (a->_flags & kFlagsCharacter)
- a->_z = a->_top + a->height();
+ a->setZ(a->getFrameY() + a->height());
}
_modCounter++;
@@ -442,13 +357,13 @@ void CommandExec::runList(CommandList::iterator first, CommandList::iterator las
_ctxt.suspend = false;
for ( ; first != last; first++) {
- if (_engineFlags & kEngineQuit)
+ if (_vm->quit())
break;
CommandPtr cmd = *first;
if (cmd->_flagsOn & kFlagsGlobal) {
- useFlags = _commandFlags | kFlagsGlobal;
+ useFlags = _globalFlags | kFlagsGlobal;
useLocalFlags = false;
} else {
useFlags = _vm->getLocationFlags();
@@ -532,239 +447,6 @@ CommandExec_ns::~CommandExec_ns() {
}
-//
-// ZONE TYPE: EXAMINE
-//
-
-void Parallaction::enterCommentMode(ZonePtr z) {
- if (!z) {
- return;
- }
-
- _commentZone = z;
-
- ExamineData *data = _commentZone->u.examine;
-
- if (!data->_description) {
- return;
- }
-
- // TODO: move this balloons stuff into DialogueManager and BalloonManager
- if (getGameType() == GType_Nippon) {
- int id;
- if (data->_filename) {
- if (data->_cnv == 0) {
- data->_cnv = _disk->loadStatic(data->_filename);
- }
-
- _gfx->setHalfbriteMode(true);
- _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0);
- Common::Rect r;
- data->_cnv->getRect(0, r);
- id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2);
- _gfx->setItemFrame(id, 0);
- id = _gfx->setItem(_char._head, 100, 152);
- _gfx->setItemFrame(id, 0);
- } else {
- _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0);
- id = _gfx->setItem(_char._talk, 190, 80);
- _gfx->setItemFrame(id, 0);
- }
- } else
- if (getGameType() == GType_BRA) {
- _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, 0);
- int id = _gfx->setItem(_char._talk, 10, 80);
- _gfx->setItemFrame(id, 0);
- }
-
- _input->_inputMode = Input::kInputModeComment;
-}
-
-void Parallaction::exitCommentMode() {
- _input->_inputMode = Input::kInputModeGame;
-
- hideDialogueStuff();
- _gfx->setHalfbriteMode(false);
-
- _cmdExec->run(_commentZone->_commands, _commentZone);
- _commentZone = nullZonePtr;
-}
-
-void Parallaction::runCommentFrame() {
- if (_input->_inputMode != Input::kInputModeComment) {
- return;
- }
-
- if (_input->getLastButtonEvent() == kMouseLeftUp) {
- exitCommentMode();
- }
-}
-
-
-uint16 Parallaction::runZone(ZonePtr z) {
- debugC(3, kDebugExec, "runZone (%s)", z->_name);
-
- uint16 subtype = z->_type & 0xFFFF;
-
- debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16);
- switch(subtype) {
-
- case kZoneExamine:
- enterCommentMode(z);
- return 0;
-
- case kZoneGet:
- if (z->_flags & kFlagsFixed) break;
- if (pickupItem(z) != 0) {
- return 1;
- }
- z->_flags |= kFlagsRemove;
- break;
-
- case kZoneDoor:
- if (z->_flags & kFlagsLocked) break;
- z->_flags ^= kFlagsClosed;
- updateDoor(z);
- break;
-
- case kZoneHear:
- _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60);
- break;
-
- case kZoneSpeak:
- enterDialogueMode(z);
- return 0;
- }
-
- debugC(3, kDebugExec, "runZone completed");
-
- _cmdExec->run(z->_commands, z);
-
- return 0;
-}
-
-//
-// ZONE TYPE: DOOR
-//
-void Parallaction::updateDoor(ZonePtr z) {
-
- if (z->u.door->gfxobj) {
- uint frame = (z->_flags & kFlagsClosed ? 0 : 1);
-// z->u.door->gfxobj->setFrame(frame);
- z->u.door->gfxobj->frame = frame;
- }
-
- return;
-}
-
-
-
-//
-// ZONE TYPE: GET
-//
-
-int16 Parallaction::pickupItem(ZonePtr z) {
- int r = addInventoryItem(z->u.get->_icon);
- if (r != -1) {
- _gfx->showGfxObj(z->u.get->gfxobj, false);
- }
-
- return (r == -1);
-}
-
-
-
-ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
-// printf("hitZone(%i, %i, %i)", type, x, y);
-
- uint16 _di = y;
- uint16 _si = x;
-
- for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) {
-// printf("Zone name: %s", z->_name);
-
- ZonePtr z = *it;
-
- if (z->_flags & kFlagsRemove) continue;
-
- Common::Rect r;
- z->getRect(r);
- r.right++; // adjust border because Common::Rect doesn't include bottom-right edge
- r.bottom++;
-
- r.grow(-1); // allows some tolerance for mouse click
-
- if (!r.contains(_si, _di)) {
-
- // out of Zone, so look for special values
- if ((z->_left == -2) || (z->_left == -3)) {
-
- // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs
- // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine,
- // but we need to check it separately here. The same workaround is applied in freeZones.
- if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) ||
- (((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) {
-
- // special Zone
- if ((type == 0) && ((z->_type & 0xFFFF0000) == 0))
- return z;
- if (z->_type == type)
- return z;
- if ((z->_type & 0xFFFF0000) == type)
- return z;
-
- }
- }
-
- if (z->_left != -1)
- continue;
- if (_si < _char._ani->_left)
- continue;
- if (_si > (_char._ani->_left + _char._ani->width()))
- continue;
- if (_di < _char._ani->_top)
- continue;
- if (_di > (_char._ani->_top + _char._ani->height()))
- continue;
-
- }
-
- // normal Zone
- if ((type == 0) && ((z->_type & 0xFFFF0000) == 0))
- return z;
- if (z->_type == type)
- return z;
- if ((z->_type & 0xFFFF0000) == type)
- return z;
-
- }
-
-
- int16 _a, _b, _c, _d, _e, _f;
- for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) {
-
- AnimationPtr a = *ait;
-
- _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
- _e = ((_si >= a->_left + a->width()) || (_si <= a->_left)) ? 0 : 1; // _e: horizontal range
- _f = ((_di >= a->_top + a->height()) || (_di <= a->_top)) ? 0 : 1; // _f: vertical range
-
- _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
- _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object
- _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type
-
- if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) {
-
- return a;
-
- }
-
- }
-
- return nullZonePtr;
-}
-
-
void CommandExec_ns::init() {
Common::Array<const Opcode*> *table = 0;
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index 2a379828ae..e84dad34aa 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -698,7 +698,7 @@ void Parallaction_br::initFonts() {
// fonts/vanya/16
_menuFont = _disk->loadFont("natasha");
- _dialogueFont = _disk->loadFont("sonya");
+ _dialogueFont = _disk->loadFont("vanya");
Common::MemoryReadStream stream(_amigaTopazFont, 2600, false);
_labelFont = new AmigaFont(stream);
}
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index aa02253cb1..8eb9753edd 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,7 @@
namespace Parallaction {
-GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3) {
+GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : _frames(frames), _keep(true), x(0), y(0), z(0), _flags(kGfxObjNormal), type(objType), frame(0), layer(3), scale(100) {
if (name) {
_name = strdup(name);
} else {
@@ -180,9 +180,9 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) {
data = obj->getData(obj->frame);
if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) {
- blt(rect, data, &surf, obj->layer, obj->transparentKey);
+ blt(rect, data, &surf, obj->layer, obj->scale, obj->transparentKey);
} else {
- unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey);
+ unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->scale, obj->transparentKey);
}
}
@@ -233,7 +233,7 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf
blt(r, _unpackedBitmap, surf, z, transparentColor);
}
#endif
-void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) {
byte *d = _unpackedBitmap;
uint pixelsLeftInLine = r.width();
@@ -259,11 +259,154 @@ void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surf
d += repeat;
}
- blt(r, _unpackedBitmap, surf, z, transparentColor);
+ blt(r, _unpackedBitmap, surf, z, scale, transparentColor);
+}
+
+
+void Gfx::bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) {
+ if (scale == 100) {
+ // use optimized path
+ bltMaskNoScale(r, data, surf, z, transparentColor);
+ return;
+ }
+
+ Common::Rect q(r);
+ Common::Rect clipper(surf->w, surf->h);
+ q.clip(clipper);
+ if (!q.isValidRect()) return;
+
+ uint inc = r.width() * (100 - scale);
+ uint thr = r.width() * 100;
+ uint xAccum = 0, yAccum = 0;
+
+ Common::Point dp;
+ dp.x = q.left + (r.width() * (100 - scale)) / 200;
+ dp.y = q.top + (r.height() * (100 - scale)) / 100;
+ q.translate(-r.left, -r.top);
+ byte *s = data + q.left + q.top * r.width();
+ byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
+
+ uint line = 0, col = 0;
+
+ for (uint16 i = 0; i < q.height(); i++) {
+ yAccum += inc;
+
+ if (yAccum >= thr) {
+ yAccum -= thr;
+ s += r.width();
+ continue;
+ }
+
+ xAccum = 0;
+ byte *d2 = d;
+ col = 0;
+
+ for (uint16 j = 0; j < q.width(); j++) {
+ xAccum += inc;
+
+ if (xAccum >= thr) {
+ xAccum -= thr;
+ s++;
+ continue;
+ }
+
+ if (*s != transparentColor) {
+ byte v = _backgroundInfo->mask.getValue(dp.x + col, dp.y + line);
+ if (z >= v) *d2 = *s;
+ }
+
+ s++;
+ d2++;
+ col++;
+ }
+
+ s += r.width() - q.width();
+ d += surf->w;
+ line++;
+ }
+
+}
+
+void Gfx::bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+ if (!_backgroundInfo->mask.data || (z == LAYER_FOREGROUND)) {
+ // use optimized path
+ bltNoMaskNoScale(r, data, surf, transparentColor);
+ return;
+ }
+
+ Common::Point dp;
+ Common::Rect q(r);
+
+ Common::Rect clipper(surf->w, surf->h);
+
+ q.clip(clipper);
+ if (!q.isValidRect()) return;
+
+ dp.x = q.left;
+ dp.y = q.top;
+
+ q.translate(-r.left, -r.top);
+
+ byte *s = data + q.left + q.top * r.width();
+ byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
+
+ uint sPitch = r.width() - q.width();
+ uint dPitch = surf->w - q.width();
+
+ for (uint16 i = 0; i < q.height(); i++) {
+
+ for (uint16 j = 0; j < q.width(); j++) {
+ if (*s != transparentColor) {
+ byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i);
+ if (z >= v) *d = *s;
+ }
+
+ s++;
+ d++;
+ }
+
+ s += sPitch;
+ d += dPitch;
+ }
+
}
+void Gfx::bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor) {
+ Common::Point dp;
+ Common::Rect q(r);
-void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+ Common::Rect clipper(surf->w, surf->h);
+
+ q.clip(clipper);
+ if (!q.isValidRect()) return;
+
+ dp.x = q.left;
+ dp.y = q.top;
+
+ q.translate(-r.left, -r.top);
+
+ byte *s = data + q.left + q.top * r.width();
+ byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
+
+ uint sPitch = r.width() - q.width();
+ uint dPitch = surf->w - q.width();
+
+ for (uint16 i = q.top; i < q.bottom; i++) {
+ for (uint16 j = q.left; j < q.right; j++) {
+ if (*s != transparentColor)
+ *d = *s;
+
+ s++;
+ d++;
+ }
+
+ s += sPitch;
+ d += dPitch;
+ }
+}
+
+
+void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor) {
Common::Point dp;
Common::Rect q(r);
@@ -291,8 +434,8 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16
for (uint16 j = 0; j < q.width(); j++) {
if (*s != transparentColor) {
- if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
- byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
+ if (_backgroundInfo->mask.data && (z < LAYER_FOREGROUND)) {
+ byte v = _backgroundInfo->mask.getValue(dp.x + j, dp.y + i);
if (z >= v) *d = 5;
} else {
*d = 5;
@@ -308,40 +451,7 @@ void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16
}
} else {
- if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
-
- for (uint16 i = 0; i < q.height(); i++) {
-
- for (uint16 j = 0; j < q.width(); j++) {
- if (*s != transparentColor) {
- byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
- if (z >= v) *d = *s;
- }
-
- s++;
- d++;
- }
-
- s += sPitch;
- d += dPitch;
- }
-
- } else {
-
- for (uint16 i = q.top; i < q.bottom; i++) {
- for (uint16 j = q.left; j < q.right; j++) {
- if (*s != transparentColor)
- *d = *s;
-
- s++;
- d++;
- }
-
- s += sPitch;
- d += dPitch;
- }
-
- }
+ bltMaskScale(r, data, surf, z, scale, transparentColor);
}
}
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index a31b7f4994..2bd3935f01 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -34,8 +34,9 @@
namespace Parallaction {
// this is the size of the receiving buffer for unpacked frames,
-// since BRA uses some insanely big animations.
-#define MAXIMUM_UNPACKED_BITMAP_SIZE 640*401
+// since BRA uses some insanely big animations (the largest is
+// part0/ani/dino.ani).
+#define MAXIMUM_UNPACKED_BITMAP_SIZE 641*401
void Gfx::registerVar(const Common::String &name, int32 initialValue) {
@@ -251,7 +252,7 @@ void Gfx::setPalette(Palette pal) {
byte sysPal[256*4];
uint n = pal.fillRGBA(sysPal);
- g_system->setPalette(sysPal, 0, n);
+ _vm->_system->setPalette(sysPal, 0, n);
}
void Gfx::setBlackPalette() {
@@ -269,7 +270,7 @@ void Gfx::animatePalette() {
PaletteFxRange *range;
for (uint16 i = 0; i < 4; i++) {
- range = &_backgroundInfo.ranges[i];
+ range = &_backgroundInfo->ranges[i];
if ((range->_flags & 1) == 0) continue; // animated palette
range->_timer += range->_step * 2; // update timer
@@ -327,7 +328,7 @@ void Gfx::drawInventory() {
_vm->_inventoryRenderer->getRect(r);
byte *data = _vm->_inventoryRenderer->getData();
- g_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height());
+ _vm->_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height());
}
void Gfx::drawItems() {
@@ -335,11 +336,11 @@ void Gfx::drawItems() {
return;
}
- Graphics::Surface *surf = g_system->lockScreen();
+ Graphics::Surface *surf = _vm->_system->lockScreen();
for (uint i = 0; i < _numItems; i++) {
drawGfxObject(_items[i].data, *surf, false);
}
- g_system->unlockScreen();
+ _vm->_system->unlockScreen();
}
void Gfx::drawBalloons() {
@@ -347,19 +348,19 @@ void Gfx::drawBalloons() {
return;
}
- Graphics::Surface *surf = g_system->lockScreen();
+ Graphics::Surface *surf = _vm->_system->lockScreen();
for (uint i = 0; i < _balloons.size(); i++) {
drawGfxObject(_balloons[i], *surf, false);
}
- g_system->unlockScreen();
+ _vm->_system->unlockScreen();
}
void Gfx::clearScreen() {
- g_system->clearScreen();
+ _vm->_system->clearScreen();
}
void Gfx::beginFrame() {
- _skipBackground = (_backgroundInfo.bg.pixels == 0); // don't render frame if background is missing
+ _skipBackground = (_backgroundInfo->bg.pixels == 0); // don't render frame if background is missing
if (!_skipBackground) {
int32 oldBackgroundMode = _varBackgroundMode;
@@ -370,13 +371,19 @@ void Gfx::beginFrame() {
_bitmapMask.free();
break;
case 2:
- _bitmapMask.create(_backgroundInfo.width, _backgroundInfo.height, 1);
+ _bitmapMask.create(_backgroundInfo->width, _backgroundInfo->height, 1);
byte *data = (byte*)_bitmapMask.pixels;
for (uint y = 0; y < _bitmapMask.h; y++) {
for (uint x = 0; x < _bitmapMask.w; x++) {
- *data++ = _backgroundInfo.mask.getValue(x, y);
+ *data++ = _backgroundInfo->mask.getValue(x, y);
}
}
+#if 0
+ Common::DumpFile dump;
+ dump.open("maskdump.bin");
+ dump.write(_bitmapMask.pixels, _bitmapMask.w * _bitmapMask.h);
+ dump.close();
+#endif
break;
}
}
@@ -389,7 +396,7 @@ void Gfx::beginFrame() {
warning("Path zones are supported only in Big Red Adventure");
}
- if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo.width)) {
+ if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo->width)) {
_varScrollX = 0;
} else {
_varScrollX = getVar("scroll_x");
@@ -416,41 +423,41 @@ void Gfx::updateScreen() {
if (!_skipBackground) {
// background may not cover the whole screen, so adjust bulk update size
- uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo.width);
- uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo.height);
+ uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo->width);
+ uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo->height);
byte *backgroundData = 0;
uint16 backgroundPitch = 0;
switch (_varBackgroundMode) {
case 1:
- backgroundData = (byte*)_backgroundInfo.bg.getBasePtr(_varScrollX, 0);
- backgroundPitch = _backgroundInfo.bg.pitch;
+ backgroundData = (byte*)_backgroundInfo->bg.getBasePtr(_varScrollX, 0);
+ backgroundPitch = _backgroundInfo->bg.pitch;
break;
case 2:
backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0);
backgroundPitch = _bitmapMask.pitch;
break;
}
- g_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo.x, _backgroundInfo.y, w, h);
+ _vm->_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h);
}
if (_varDrawPathZones == 1) {
- Graphics::Surface *surf = g_system->lockScreen();
+ Graphics::Surface *surf = _vm->_system->lockScreen();
ZoneList::iterator b = _vm->_location._zones.begin();
ZoneList::iterator e = _vm->_location._zones.end();
for (; b != e; b++) {
ZonePtr z = *b;
if (z->_type & kZonePath) {
- surf->frameRect(Common::Rect(z->_left, z->_top, z->_right, z->_bottom), 2);
+ surf->frameRect(Common::Rect(z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height()), 2);
}
}
- g_system->unlockScreen();
+ _vm->_system->unlockScreen();
}
_varRenderMode = _varAnimRenderMode;
// TODO: transform objects coordinates to be drawn with scrolling
- Graphics::Surface *surf = g_system->lockScreen();
+ Graphics::Surface *surf = _vm->_system->lockScreen();
drawGfxObjects(*surf);
if (_halfbrite) {
@@ -474,7 +481,7 @@ void Gfx::updateScreen() {
}
}
- g_system->unlockScreen();
+ _vm->_system->unlockScreen();
_varRenderMode = _varMiscRenderMode;
@@ -483,7 +490,7 @@ void Gfx::updateScreen() {
drawBalloons();
drawLabels();
- g_system->updateScreen();
+ _vm->_system->updateScreen();
return;
}
@@ -499,17 +506,17 @@ void Gfx::patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask)
Common::Rect r(surf.w, surf.h);
r.moveTo(x, y);
- uint16 z = (mask) ? _backgroundInfo.getLayer(y) : LAYER_FOREGROUND;
- blt(r, (byte*)surf.pixels, &_backgroundInfo.bg, z, 0);
+ uint16 z = (mask) ? _backgroundInfo->getLayer(y) : LAYER_FOREGROUND;
+ blt(r, (byte*)surf.pixels, &_backgroundInfo->bg, z, 100, 0);
}
void Gfx::fillBackground(const Common::Rect& r, byte color) {
- _backgroundInfo.bg.fillRect(r, color);
+ _backgroundInfo->bg.fillRect(r, color);
}
void Gfx::invertBackground(const Common::Rect& r) {
- byte *d = (byte*)_backgroundInfo.bg.getBasePtr(r.left, r.top);
+ byte *d = (byte*)_backgroundInfo->bg.getBasePtr(r.left, r.top);
for (int i = 0; i < r.height(); i++) {
for (int j = 0; j < r.width(); j++) {
@@ -517,7 +524,7 @@ void Gfx::invertBackground(const Common::Rect& r) {
d++;
}
- d += (_backgroundInfo.bg.pitch - r.width());
+ d += (_backgroundInfo->bg.pitch - r.width());
}
}
@@ -594,30 +601,41 @@ void Gfx::updateFloatingLabel() {
return;
}
- int16 _si, _di;
-
- Common::Point cursor;
- _vm->_input->getCursorPos(cursor);
+ struct FloatingLabelTraits {
+ Common::Point _offsetWithItem;
+ Common::Point _offsetWithoutItem;
+ int _minX;
+ int _minY;
+ int _maxX;
+ int _maxY;
+ } *traits;
Common::Rect r;
_labels[_floatingLabel]->getRect(0, r);
- if (_vm->_input->_activeItem._id != 0) {
- _si = cursor.x + 16 - r.width()/2;
- _di = cursor.y + 34;
+ if (_vm->getGameType() == GType_Nippon) {
+ FloatingLabelTraits traits_NS = {
+ Common::Point(16 - r.width()/2, 34),
+ Common::Point(8 - r.width()/2, 21),
+ 0, 0, _vm->_screenWidth - r.width(), 190
+ };
+ traits = &traits_NS;
} else {
- _si = cursor.x + 8 - r.width()/2;
- _di = cursor.y + 21;
+ // FIXME: _maxY for BRA is not constant (390), but depends on _vm->_subtitleY
+ FloatingLabelTraits traits_BR = {
+ Common::Point(34 - r.width()/2, 70),
+ Common::Point(16 - r.width()/2, 37),
+ 0, 0, _vm->_screenWidth - r.width(), 390
+ };
+ traits = &traits_BR;
}
- if (_si < 0) _si = 0;
- if (_di > 190) _di = 190;
-
- if (r.width() + _si > _vm->_screenWidth)
- _si = _vm->_screenWidth - r.width();
+ Common::Point cursor;
+ _vm->_input->getCursorPos(cursor);
+ Common::Point offset = (_vm->_input->_activeItem._id) ? traits->_offsetWithItem : traits->_offsetWithoutItem;
- _labels[_floatingLabel]->x = _si;
- _labels[_floatingLabel]->y = _di;
+ _labels[_floatingLabel]->x = CLIP(cursor.x + offset.x, traits->_minX, traits->_maxX);
+ _labels[_floatingLabel]->y = CLIP(cursor.y + offset.y, traits->_minY, traits->_maxY);
}
@@ -697,13 +715,13 @@ void Gfx::drawLabels() {
updateFloatingLabel();
- Graphics::Surface* surf = g_system->lockScreen();
+ Graphics::Surface* surf = _vm->_system->lockScreen();
for (uint i = 0; i < _labels.size(); i++) {
drawGfxObject(_labels[i], *surf, false);
}
- g_system->unlockScreen();
+ _vm->_system->unlockScreen();
}
@@ -724,17 +742,17 @@ void Gfx::copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surf
}
void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) {
- copyRect(r, _backgroundInfo.bg, dst);
+ copyRect(r, _backgroundInfo->bg, dst);
}
Gfx::Gfx(Parallaction* vm) :
_vm(vm), _disk(vm->_disk) {
- g_system->beginGFXTransaction();
- g_system->initSize(_vm->_screenWidth, _vm->_screenHeight);
+ _vm->_system->beginGFXTransaction();
+ _vm->_system->initSize(_vm->_screenWidth, _vm->_screenHeight);
_vm->initCommonGFX(_vm->getGameType() == GType_BRA);
- g_system->endGFXTransaction();
+ _vm->_system->endGFXTransaction();
setPalette(_palette);
@@ -744,6 +762,8 @@ Gfx::Gfx(Parallaction* vm) :
_screenX = 0;
_screenY = 0;
+ _backgroundInfo = 0;
+
_halfbrite = false;
_hbCircleRadius = 0;
@@ -766,7 +786,6 @@ Gfx::Gfx(Parallaction* vm) :
BackgroundInfo paletteInfo;
_disk->loadSlide(paletteInfo, "pointer");
_backupPal.clone(paletteInfo.palette);
- paletteInfo.free();
}
return;
@@ -774,7 +793,8 @@ Gfx::Gfx(Parallaction* vm) :
Gfx::~Gfx() {
- freeBackground();
+ delete _backgroundInfo;
+
freeLabels();
delete []_unpackedBitmap;
@@ -829,17 +849,11 @@ void Gfx::freeItems() {
_numItems = 0;
}
-void Gfx::freeBackground() {
- _backgroundInfo.free();
-}
-
-void Gfx::setBackground(uint type, const char* name, const char* mask, const char* path) {
-
- freeBackground();
+void Gfx::setBackground(uint type, BackgroundInfo *info) {
+ delete _backgroundInfo;
+ _backgroundInfo = info;
if (type == kBackgroundLocation) {
- _disk->loadScenery(_backgroundInfo, name, mask, path);
-
// The PC version of BRA needs the entries 20-31 of the palette to be constant, but
// the background resource files are screwed up. The right colors come from an unused
// bitmap (pointer.bmp). Nothing is known about the Amiga version so far.
@@ -847,19 +861,17 @@ void Gfx::setBackground(uint type, const char* name, const char* mask, const cha
int r, g, b;
for (uint i = 16; i < 32; i++) {
_backupPal.getEntry(i, r, g, b);
- _backgroundInfo.palette.setEntry(i, r, g, b);
+ _backgroundInfo->palette.setEntry(i, r, g, b);
}
}
- setPalette(_backgroundInfo.palette);
- _palette.clone(_backgroundInfo.palette);
+ setPalette(_backgroundInfo->palette);
+ _palette.clone(_backgroundInfo->palette);
} else {
- _disk->loadSlide(_backgroundInfo, name);
for (uint i = 0; i < 6; i++)
- _backgroundInfo.ranges[i]._flags = 0; // disable palette cycling for slides
- setPalette(_backgroundInfo.palette);
+ _backgroundInfo->ranges[i]._flags = 0; // disable palette cycling for slides
+ setPalette(_backgroundInfo->palette);
}
-
}
} // namespace Parallaction
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index 52b7a4b870..ac9f096d7e 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -209,6 +209,42 @@ public:
return (m >> n) & 3;
}
+ inline byte* getPtr(uint16 x, uint16 y) const {
+ return data + (x >> 2) + y * internalWidth;
+ }
+
+ void bltOr(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height) {
+ assert((width <= w) && (width <= src.w) && (height <= h) && (height <= src.h));
+
+ byte *s = src.getPtr(sx, sy);
+ byte *d = getPtr(dx, dy);
+
+ // this code assumes buffers are aligned on 4-pixels boundaries, as the original does
+ uint16 linewidth = width >> 2;
+ for (uint16 i = 0; i < height; i++) {
+ for (uint16 j = 0; j < linewidth; j++) {
+ *d++ |= *s++;
+ }
+ d += internalWidth - linewidth;
+ s += src.internalWidth - linewidth;
+ }
+ }
+
+ void bltCopy(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height) {
+ assert((width <= w) && (width <= src.w) && (height <= h) && (height <= src.h));
+
+ byte *s = src.getPtr(sx, sy);
+ byte *d = getPtr(dx, dy);
+
+ // this code assumes buffers are aligned on 4-pixels boundaries, as the original does
+ for (uint16 i = 0; i < height; i++) {
+ memcpy(d, s, (width >> 2));
+ d += internalWidth;
+ s += src.internalWidth;
+ }
+ }
+
+
};
@@ -277,6 +313,7 @@ struct Cnv : public Frames {
uint16 _height; //
byte** field_8; // unused
byte* _data;
+ bool _freeData;
public:
Cnv() {
@@ -284,12 +321,14 @@ public:
_data = NULL;
}
- Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data) : _count(numFrames), _width(width), _height(height), _data(data) {
+ Cnv(uint16 numFrames, uint16 width, uint16 height, byte* data, bool freeData = false)
+ : _count(numFrames), _width(width), _height(height), _data(data), _freeData(freeData) {
}
~Cnv() {
- free(_data);
+ if (_freeData)
+ free(_data);
}
byte* getFramePtr(uint16 index) {
@@ -374,6 +413,7 @@ public:
uint frame;
uint layer;
uint transparentKey;
+ uint scale;
GfxObj(uint type, Frames *frames, const char *name = NULL);
virtual ~GfxObj();
@@ -419,7 +459,9 @@ struct BackgroundInfo {
int layers[4];
PaletteFxRange ranges[6];
- BackgroundInfo() : x(0), y(0), width(0), height(0) {
+ bool hasMask;
+
+ BackgroundInfo() : x(0), y(0), width(0), height(0), hasMask(false) {
layers[0] = layers[1] = layers[2] = layers[3] = 0;
memset(ranges, 0, sizeof(ranges));
}
@@ -436,7 +478,7 @@ struct BackgroundInfo {
return LAYER_FOREGROUND;
}
- void free() {
+ ~BackgroundInfo() {
bg.free();
mask.free();
path.free();
@@ -457,13 +499,19 @@ enum {
class BalloonManager {
public:
+ enum TextColor {
+ kSelectedColor = 0,
+ kUnselectedColor = 1,
+ kNormalColor = 2
+ };
+
virtual ~BalloonManager() { }
virtual void freeBalloons() = 0;
virtual int setLocationBalloon(char *text, bool endGame) = 0;
- virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0;
- virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0;
- virtual void setBalloonText(uint id, char *text, byte textColor) = 0;
+ virtual int setDialogueBalloon(char *text, uint16 winding, TextColor textColor) = 0;
+ virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, TextColor textColor) = 0;
+ virtual void setBalloonText(uint id, char *text, TextColor textColor) = 0;
virtual int hitTestDialogueBalloon(int x, int y) = 0;
};
@@ -511,8 +559,8 @@ public:
void freeItems();
// background surface
- BackgroundInfo _backgroundInfo;
- void setBackground(uint type, const char* name, const char* mask, const char* path);
+ BackgroundInfo *_backgroundInfo;
+ void setBackground(uint type, BackgroundInfo *info);
void patchBackground(Graphics::Surface &surf, int16 x, int16 y, bool mask = false);
void grabBackground(const Common::Rect& r, Graphics::Surface &dst);
void fillBackground(const Common::Rect& r, byte color);
@@ -602,8 +650,12 @@ public:
void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color);
void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene);
- void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor);
- void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor);
+ void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor);
+ void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor);
+
+ void bltMaskScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor);
+ void bltMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor);
+ void bltNoMaskNoScale(const Common::Rect& r, byte *data, Graphics::Surface *surf, byte transparentColor);
};
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index b10237046e..c687a15026 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -28,6 +28,7 @@
#include "parallaction/gui.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
+#include "parallaction/saveload.h"
namespace Parallaction {
@@ -40,11 +41,11 @@ protected:
Palette blackPal;
Palette pal;
- Parallaction_br *_vm;
+ Parallaction *_vm;
int _fadeSteps;
public:
- SplashInputState_BR(Parallaction_br *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
}
virtual MenuInputState* run() {
@@ -52,8 +53,6 @@ public:
pal.fadeTo(blackPal, 1);
_vm->_gfx->setPalette(pal);
_fadeSteps--;
- // TODO: properly implement timers to avoid delay calls
- _vm->_system->delayMillis(20);
return this;
}
@@ -65,19 +64,17 @@ public:
uint32 curTime = _vm->_system->getMillis();
if (curTime - _startTime > _timeOut) {
_fadeSteps = 64;
- pal.clone(_vm->_gfx->_backgroundInfo.palette);
+ pal.clone(_vm->_gfx->_backgroundInfo->palette);
}
return this;
}
virtual void enter() {
_vm->_gfx->clearScreen();
- _vm->_gfx->setBackground(kBackgroundSlide, _slideName.c_str(), 0, 0);
- _vm->_gfx->_backgroundInfo.x = (_vm->_screenWidth - _vm->_gfx->_backgroundInfo.width) >> 1;
- _vm->_gfx->_backgroundInfo.y = (_vm->_screenHeight - _vm->_gfx->_backgroundInfo.height) >> 1;
+ _vm->showSlide(_slideName.c_str(), CENTER_LABEL_HORIZONTAL, CENTER_LABEL_VERTICAL);
_vm->_input->setMouseState(MOUSE_DISABLED);
- _startTime = g_system->getMillis();
+ _startTime = _vm->_system->getMillis();
_fadeSteps = -1;
}
};
@@ -154,6 +151,8 @@ class MainMenuInputState_BR : public MenuInputState {
static const char *_menuStrings[NUM_MENULINES];
static const MenuOptions _options[NUM_MENULINES];
+ static const char *_firstLocation[];
+
int _availItems;
int _selection;
@@ -168,16 +167,18 @@ class MainMenuInputState_BR : public MenuInputState {
void performChoice(int selectedItem) {
switch (selectedItem) {
- case kMenuQuit:
- _engineFlags |= kEngineQuit;
+ case kMenuQuit: {
+ _vm->_quit = true;
+ _vm->quitGame();
break;
+ }
case kMenuLoadGame:
warning("loadgame not yet implemented");
break;
default:
- _vm->startPart(selectedItem);
+ _vm->scheduleLocationSwitch(_firstLocation[selectedItem]);
}
}
@@ -215,30 +216,40 @@ public:
virtual void enter() {
_vm->_gfx->clearScreen();
- _vm->_gfx->setBackground(kBackgroundSlide, "tbra", 0, 0);
+ int x = 0, y = 0, i = 0;
if (_vm->getPlatform() == Common::kPlatformPC) {
- _vm->_gfx->_backgroundInfo.x = 20;
- _vm->_gfx->_backgroundInfo.y = 50;
+ x = 20;
+ y = 50;
}
+ _vm->showSlide("tbra", x, y);
+
+ _availItems = 4;
- // TODO: load progress from savefile
- int progress = 3;
- _availItems = 4 + progress;
+ bool complete[3];
+ _vm->_saveLoad->getGamePartProgress(complete, 3);
+ for (i = 0; i < 3 && complete[i]; i++, _availItems++) ;
// TODO: keep track of and destroy menu item frames/surfaces
- int i;
for (i = 0; i < _availItems; i++) {
_lines[i] = new GfxObj(0, renderMenuItem(_menuStrings[i]), "MenuItem");
uint id = _vm->_gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF);
_vm->_gfx->setItemFrame(id, 0);
}
_selection = -1;
- _vm->setArrowCursor();
+ _vm->_input->setArrowCursor();
_vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
}
};
+const char *MainMenuInputState_BR::_firstLocation[] = {
+ "intro.0",
+ "museo.1",
+ "start.2",
+ "bolscoi.3",
+ "treno.4"
+};
+
const char *MainMenuInputState_BR::_menuStrings[NUM_MENULINES] = {
"SEE INTRO",
"NEW GAME",
@@ -265,29 +276,24 @@ const MainMenuInputState_BR::MenuOptions MainMenuInputState_BR::_options[NUM_MEN
-void Parallaction_br::startGui() {
+void Parallaction_br::startGui(bool showSplash) {
_menuHelper = new MenuInputHelper;
- new SplashInputState0_BR(this, _menuHelper);
- new SplashInputState1_BR(this, _menuHelper);
- new MainMenuInputState_BR(this, _menuHelper);
- _menuHelper->setState("intro0");
- _input->_inputMode = Input::kInputModeMenu;
-
- do {
- _input->readInput();
- if (!_menuHelper->run()) break;
- _gfx->beginFrame();
- _gfx->updateScreen();
- } while (true);
+ new MainMenuInputState_BR(this, _menuHelper);
- delete _menuHelper;
- _menuHelper = 0;
+ if (showSplash) {
+ new SplashInputState0_BR(this, _menuHelper);
+ new SplashInputState1_BR(this, _menuHelper);
+ _menuHelper->setState("intro0");
+ } else {
+ _menuHelper->setState("mainmenu");
+ }
- _input->_inputMode = Input::kInputModeGame;
+ _input->_inputMode = Input::kInputModeMenu;
}
+
} // namespace Parallaction
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 815c27bd1c..73cc1be12e 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -29,6 +29,7 @@
#include "parallaction/gui.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
@@ -41,14 +42,14 @@ protected:
Common::String _nextState;
uint32 _startTime;
- Parallaction_ns *_vm;
+ Parallaction *_vm;
public:
- SplashInputState_NS(Parallaction_ns *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
}
virtual MenuInputState* run() {
- uint32 curTime = g_system->getMillis();
+ uint32 curTime = _vm->_system->getMillis();
if (curTime - _startTime > _timeOut) {
_vm->freeBackground();
return _helper->getState(_nextState);
@@ -59,14 +60,14 @@ public:
virtual void enter() {
_vm->_input->setMouseState(MOUSE_DISABLED);
_vm->showSlide(_slideName.c_str());
- _startTime = g_system->getMillis();
+ _startTime = _vm->_system->getMillis();
}
};
class SplashInputState0_NS : public SplashInputState_NS {
public:
- SplashInputState0_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) {
+ SplashInputState0_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro0", helper) {
_slideName = "intro";
_timeOut = 2000;
_nextState = "intro1";
@@ -76,7 +77,7 @@ public:
class SplashInputState1_NS : public SplashInputState_NS {
public:
- SplashInputState1_NS(Parallaction_ns *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) {
+ SplashInputState1_NS(Parallaction *vm, MenuInputHelper *helper) : SplashInputState_NS(vm, "intro1", helper) {
_slideName = "minintro";
_timeOut = 2000;
_nextState = "chooselanguage";
@@ -111,10 +112,10 @@ class ChooseLanguageInputState_NS : public MenuInputState {
static const Common::Rect _amigaLanguageSelectBlocks[4];
const Common::Rect *_blocks;
- Parallaction_ns *_vm;
+ Parallaction *_vm;
public:
- ChooseLanguageInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) {
+ ChooseLanguageInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("chooselanguage", helper), _vm(vm) {
_allowChoice = false;
_nextState = "selectgame";
@@ -178,7 +179,7 @@ public:
uint id = _vm->_gfx->createLabel(_vm->_introFont, "SELECT LANGUAGE", 1);
_vm->_gfx->showLabel(id, 60, 30);
- _vm->setArrowCursor();
+ _vm->_input->setArrowCursor();
}
};
@@ -203,13 +204,13 @@ class SelectGameInputState_NS : public MenuInputState {
uint _labels[2];
- Parallaction_ns *_vm;
+ Parallaction *_vm;
static const char *newGameMsg[4];
static const char *loadGameMsg[4];
public:
- SelectGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) {
+ SelectGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectgame", helper), _vm(vm) {
_choice = 0;
_oldChoice = -1;
@@ -271,10 +272,10 @@ const char *SelectGameInputState_NS::loadGameMsg[4] = {
class LoadGameInputState_NS : public MenuInputState {
bool _result;
- Parallaction_ns *_vm;
+ Parallaction *_vm;
public:
- LoadGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
+ LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
virtual MenuInputState* run() {
if (!_result) {
@@ -284,19 +285,19 @@ public:
}
virtual void enter() {
- _result = _vm->loadGame();
+ _result = _vm->_saveLoad->loadGame();
}
};
class NewGameInputState_NS : public MenuInputState {
- Parallaction_ns *_vm;
+ Parallaction *_vm;
static const char *introMsg3[4];
public:
- NewGameInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) {
+ NewGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("newgame", helper), _vm(vm) {
}
virtual MenuInputState* run() {
@@ -344,14 +345,15 @@ const char *NewGameInputState_NS::introMsg3[4] = {
class StartDemoInputState_NS : public MenuInputState {
- Parallaction_ns *_vm;
+ Parallaction *_vm;
public:
- StartDemoInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) {
+ StartDemoInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("startdemo", helper), _vm(vm) {
}
virtual MenuInputState* run() {
_vm->scheduleLocationSwitch("fognedemo.dough");
+ _vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
return 0;
}
@@ -371,7 +373,7 @@ class SelectCharacterInputState_NS : public MenuInputState {
static const Common::Rect codeSelectBlocks[9];
static const Common::Rect codeTrueBlocks[9];
- Parallaction_ns *_vm;
+ Parallaction *_vm;
int guiGetSelectedBlock(const Common::Point &p) {
@@ -388,7 +390,7 @@ class SelectCharacterInputState_NS : public MenuInputState {
_vm->_gfx->invertBackground(codeTrueBlocks[selection]);
_vm->_gfx->updateScreen();
_vm->beep();
- g_system->delayMillis(100);
+ _vm->_system->delayMillis(100);
_vm->_gfx->invertBackground(codeTrueBlocks[selection]);
_vm->_gfx->updateScreen();
}
@@ -424,7 +426,7 @@ class SelectCharacterInputState_NS : public MenuInputState {
public:
- SelectCharacterInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) {
+ SelectCharacterInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("selectcharacter", helper), _vm(vm) {
_keys = (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) ? _amigaKeys : _pcKeys;
_block.create(BLOCK_WIDTH, BLOCK_HEIGHT, 1);
}
@@ -443,7 +445,7 @@ public:
}
void delay() {
- if (g_system->getMillis() - _startTime < 2000) {
+ if (_vm->_system->getMillis() - _startTime < 2000) {
return;
}
cleanup();
@@ -485,7 +487,7 @@ public:
_vm->_gfx->patchBackground(_emptySlots, SLOT_X, SLOT_Y, false);
_vm->_gfx->hideLabel(_labels[0]);
_vm->_gfx->showLabel(_labels[1], 60, 30);
- _startTime = g_system->getMillis();
+ _startTime = _vm->_system->getMillis();
_state = DELAY;
}
@@ -508,7 +510,6 @@ public:
error("If you read this, either your CPU or transivity is broken (we believe the former).");
}
- _vm->_inTestResult = false;
_vm->cleanupGame();
_vm->scheduleLocationSwitch(_charStartLocation[character]);
}
@@ -555,7 +556,7 @@ public:
cleanup();
- _vm->setArrowCursor();
+ _vm->_input->setArrowCursor();
_vm->_input->setMouseState(MOUSE_ENABLED_SHOW);
_state = CHOICE;
}
@@ -620,7 +621,7 @@ const Common::Rect SelectCharacterInputState_NS::codeTrueBlocks[9] = {
class ShowCreditsInputState_NS : public MenuInputState {
- Parallaction_ns *_vm;
+ Parallaction *_vm;
int _current;
uint32 _startTime;
@@ -632,7 +633,7 @@ class ShowCreditsInputState_NS : public MenuInputState {
static const Credit _credits[6];
public:
- ShowCreditsInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
+ ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
}
void drawCurrentLabel() {
@@ -646,14 +647,14 @@ public:
virtual MenuInputState* run() {
if (_current == -1) {
- _startTime = g_system->getMillis();
+ _startTime = _vm->_system->getMillis();
_current = 0;
drawCurrentLabel();
return this;
}
int event = _vm->_input->getLastButtonEvent();
- uint32 curTime = g_system->getMillis();
+ uint32 curTime = _vm->_system->getMillis();
if ((event == kMouseLeftUp) || (curTime - _startTime > 5500)) {
_current++;
_startTime = curTime;
@@ -685,11 +686,11 @@ const ShowCreditsInputState_NS::Credit ShowCreditsInputState_NS::_credits[6] = {
};
class EndIntroInputState_NS : public MenuInputState {
- Parallaction_ns *_vm;
+ Parallaction *_vm;
bool _isDemo;
public:
- EndIntroInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) {
+ EndIntroInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endintro", helper), _vm(vm) {
_isDemo = (_vm->getFeatures() & GF_DEMO) != 0;
}
@@ -701,7 +702,8 @@ public:
}
if (_isDemo) {
- _engineFlags |= kEngineQuit;
+ _vm->_quit = true;
+ _vm->quitGame();
return 0;
}
@@ -722,7 +724,7 @@ public:
class EndPartInputState_NS : public MenuInputState {
- Parallaction_ns *_vm;
+ Parallaction *_vm;
bool _allPartsComplete;
// part completion messages
@@ -738,7 +740,7 @@ class EndPartInputState_NS : public MenuInputState {
public:
- EndPartInputState_NS(Parallaction_ns *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) {
+ EndPartInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("endpart", helper), _vm(vm) {
}
virtual MenuInputState* run() {
@@ -758,20 +760,23 @@ public:
}
virtual void enter() {
- _allPartsComplete = _vm->allPartsComplete();
+ bool completed[3];
+ _vm->_saveLoad->getGamePartProgress(completed, 3);
+ _allPartsComplete = (completed[0] && completed[1] && completed[2]);
_vm->_input->setMouseState(MOUSE_DISABLED);
+ uint16 language = _vm->getInternLanguage();
uint id[4];
if (_allPartsComplete) {
- id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[_language], 1);
- id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[_language], 1);
- id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[_language], 1);
- id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[_language], 1);
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg4[language], 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg5[language], 1);
+ id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg6[language], 1);
+ id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg7[language], 1);
} else {
- id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[_language], 1);
- id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[_language], 1);
- id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[_language], 1);
- id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[_language], 1);
+ id[0] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg0[language], 1);
+ id[1] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg1[language], 1);
+ id[2] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg2[language], 1);
+ id[3] = _vm->_gfx->createLabel(_vm->_menuFont, endMsg3[language], 1);
}
_vm->_gfx->showLabel(id[0], CENTER_LABEL_HORIZONTAL, 70);
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 287618e803..c91421e15e 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -31,6 +31,58 @@
namespace Parallaction {
+#define MOUSEARROW_WIDTH_NS 16
+#define MOUSEARROW_HEIGHT_NS 16
+
+#define MOUSECOMBO_WIDTH_NS 32 // sizes for cursor + selected inventory item
+#define MOUSECOMBO_HEIGHT_NS 32
+
+struct MouseComboProperties {
+ int _xOffset;
+ int _yOffset;
+ int _width;
+ int _height;
+};
+/*
+// TODO: improve NS's handling of normal cursor before merging cursor code.
+MouseComboProperties _mouseComboProps_NS = {
+ 7, // combo x offset (the icon from the inventory will be rendered from here)
+ 7, // combo y offset (ditto)
+ 32, // combo (arrow + icon) width
+ 32 // combo (arrow + icon) height
+};
+*/
+MouseComboProperties _mouseComboProps_BR = {
+ 8, // combo x offset (the icon from the inventory will be rendered from here)
+ 8, // combo y offset (ditto)
+ 68, // combo (arrow + icon) width
+ 68 // combo (arrow + icon) height
+};
+
+Input::Input(Parallaction *vm) : _vm(vm) {
+ _gameType = _vm->getGameType();
+ _transCurrentHoverItem = 0;
+ _hasDelayedAction = false; // actived when the character needs to move before taking an action
+ _mouseState = MOUSE_DISABLED;
+ _activeItem._index = 0;
+ _activeItem._id = 0;
+ _mouseButtons = 0;
+ _delayedActionZone = nullZonePtr;
+
+ initCursors();
+}
+
+Input::~Input() {
+ if (_gameType == GType_Nippon) {
+ delete _mouseArrow;
+ }
+
+ delete _comboArrow;
+ delete _dinoCursor;
+ delete _dougCursor;
+ delete _donnaCursor;
+}
+
// FIXME: the engine has 3 event loops. The following routine hosts the main one,
// and it's called from 8 different places in the code. There exist 2 more specialised
// loops which could possibly be merged into this one with some effort in changing
@@ -79,8 +131,9 @@ void Input::readInput() {
_mousePos = e.mouse;
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _engineFlags |= kEngineQuit;
+ _vm->_quit = true;
return;
default:
@@ -127,9 +180,9 @@ void Input::waitForButtonEvent(uint32 buttonEventMask, int32 timeout) {
}
-void Input::updateGameInput() {
+int Input::updateGameInput() {
- readInput();
+ int event = kEvNone;
if (!isMouseEnabled() ||
(_engineFlags & kEngineWalking) ||
@@ -141,44 +194,38 @@ void Input::updateGameInput() {
(_engineFlags & kEngineChangeLocation) == 0
);
- return;
+ return event;
}
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
- if (_keyPressed.keycode == Common::KEYCODE_l) _inputData._event = kEvLoadGame;
- if (_keyPressed.keycode == Common::KEYCODE_s) _inputData._event = kEvSaveGame;
+ if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame;
+ if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame;
}
- if (_inputData._event == kEvNone) {
- _inputData._mousePos = _mousePos;
+ if (event == kEvNone) {
translateGameInput();
}
+ return event;
}
-InputData* Input::updateInput() {
+int Input::updateInput() {
- _inputData._event = kEvNone;
+ int event = kEvNone;
+ readInput();
switch (_inputMode) {
- case kInputModeComment:
- case kInputModeDialogue:
- case kInputModeMenu:
- readInput();
- break;
-
case kInputModeGame:
- updateGameInput();
+ event = updateGameInput();
break;
case kInputModeInventory:
- readInput();
updateInventoryInput();
break;
}
- return &_inputData;
+ return event;
}
void Input::trackMouse(ZonePtr z) {
@@ -212,7 +259,7 @@ void Input::takeAction(ZonePtr z) {
void Input::walkTo(const Common::Point &dest) {
stopHovering();
- _vm->setArrowCursor();
+ setArrowCursor();
_vm->_char.scheduleWalk(dest.x, dest.y);
}
@@ -252,7 +299,6 @@ bool Input::translateGameInput() {
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) {
- _inputData._zone = z;
if (z->_flags & kFlagsNoWalk) {
// character doesn't need to walk to take specified action
takeAction(z);
@@ -269,7 +315,7 @@ bool Input::translateGameInput() {
}
_vm->beep();
- _vm->setArrowCursor();
+ setArrowCursor();
return true;
}
@@ -285,7 +331,7 @@ void Input::enterInventoryMode() {
_activeItem._index = (_activeItem._id >> 16) & 0xFFFF;
_engineFlags |= kEngineDragging;
} else {
- _vm->setArrowCursor();
+ setArrowCursor();
}
}
@@ -320,12 +366,12 @@ void Input::exitInventoryMode() {
_vm->closeInventory();
if (pos == -1) {
- _vm->setArrowCursor();
+ setArrowCursor();
} else {
const InventoryItem *item = _vm->getInventoryItem(pos);
if (item->_index != 0) {
_activeItem._id = item->_id;
- _vm->setInventoryCursor(item->_index);
+ setInventoryCursor(item->_index);
}
}
_vm->resumeJobs();
@@ -373,4 +419,96 @@ bool Input::isMouseEnabled() {
return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE);
}
+
+void Input::initCursors() {
+
+ _dinoCursor = _donnaCursor = _dougCursor = 0;
+
+ switch (_gameType) {
+ case GType_Nippon:
+ _comboArrow = _vm->_disk->loadPointer("pointer");
+ _mouseArrow = new Cnv(1, MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, _resMouseArrow_NS, false);
+ break;
+
+ case GType_BRA:
+ if (_vm->getPlatform() == Common::kPlatformPC) {
+ _dinoCursor = _vm->_disk->loadPointer("pointer1");
+ _dougCursor = _vm->_disk->loadPointer("pointer2");
+ _donnaCursor = _vm->_disk->loadPointer("pointer3");
+
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1);
+ _comboArrow = new SurfaceToFrames(surf);
+
+ // TODO: choose the pointer depending on the active character
+ // For now, we pick Donna's
+ _mouseArrow = _donnaCursor;
+ } else {
+ // TODO: Where are the Amiga cursors?
+ _mouseArrow = 0;
+ }
+ break;
+
+ default:
+ warning("Input::initCursors: unknown gametype");
+ }
+
+}
+
+void Input::setArrowCursor() {
+
+ switch (_gameType) {
+ case GType_Nippon:
+ debugC(1, kDebugInput, "setting mouse cursor to arrow");
+ // this stuff is needed to avoid artifacts with labels and selected items when switching cursors
+ stopHovering();
+ _activeItem._id = 0;
+ _vm->_system->setMouseCursor(_mouseArrow->getData(0), MOUSEARROW_WIDTH_NS, MOUSEARROW_HEIGHT_NS, 0, 0, 0);
+ break;
+
+ case GType_BRA: {
+ if (_vm->getPlatform() == Common::kPlatformAmiga)
+ return;
+
+ Common::Rect r;
+ _mouseArrow->getRect(0, r);
+ _vm->_system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0);
+ _vm->_system->showMouse(true);
+ _activeItem._id = 0;
+ break;
+ }
+
+ default:
+ warning("Input::setArrowCursor: unknown gametype");
+ }
+
+}
+
+void Input::setInventoryCursor(ItemName name) {
+ assert(name > 0);
+
+ switch (_gameType) {
+ case GType_Nippon: {
+ byte *v8 = _comboArrow->getData(0);
+ // FIXME: destination offseting is not clear
+ _vm->_inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH_NS + 7, MOUSECOMBO_WIDTH_NS);
+ _vm->_system->setMouseCursor(v8, MOUSECOMBO_WIDTH_NS, MOUSECOMBO_HEIGHT_NS, 0, 0, 0);
+ break;
+ }
+
+ case GType_BRA: {
+ byte *src = _mouseArrow->getData(0);
+ byte *dst = _comboArrow->getData(0);
+ memcpy(dst, src, _comboArrow->getSize(0));
+ // FIXME: destination offseting is not clear
+ _vm->_inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width);
+ _vm->_system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0);
+ }
+
+ default:
+ warning("Input::setInventoryCursor: unknown gametype");
+ }
+
+}
+
} // namespace Parallaction
diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h
index c1e912db74..e7d20c0d2e 100644
--- a/engines/parallaction/input.h
+++ b/engines/parallaction/input.h
@@ -41,14 +41,6 @@ enum {
kMouseRightDown = 8
};
-struct InputData {
- uint16 _event;
- Common::Point _mousePos;
- int16 _inventoryIndex;
- ZonePtr _zone;
- uint _label;
-};
-
enum MouseTriState {
MOUSE_ENABLED_SHOW,
MOUSE_ENABLED_HIDE,
@@ -56,10 +48,7 @@ enum MouseTriState {
};
class Input {
- void updateGameInput();
-
- // input-only
- InputData _inputData;
+ int updateGameInput();
bool _hasKeyPressEvent;
Common::KeyState _keyPressed;
@@ -69,7 +58,7 @@ class Input {
int16 _transCurrentHoverItem;
- InputData *translateInput();
+ void translateInput();
bool translateGameInput();
bool updateInventoryInput();
void takeAction(ZonePtr z);
@@ -85,6 +74,17 @@ class Input {
void enterInventoryMode();
void exitInventoryMode();
+ int _gameType;
+
+ static byte _resMouseArrow_NS[256];
+ Frames *_mouseArrow;
+ Frames *_comboArrow;
+ Frames *_dinoCursor;
+ Frames *_dougCursor;
+ Frames *_donnaCursor;
+
+ void initCursors();
+
public:
enum {
kInputModeGame = 0,
@@ -95,18 +95,8 @@ public:
};
- Input(Parallaction *vm) : _vm(vm) {
- _transCurrentHoverItem = 0;
- _hasDelayedAction = false; // actived when the character needs to move before taking an action
- _mouseState = MOUSE_DISABLED;
- _activeItem._index = 0;
- _activeItem._id = 0;
- _mouseButtons = 0;
- _delayedActionZone = nullZonePtr;
- }
-
- virtual ~Input() { }
-
+ Input(Parallaction *vm);
+ virtual ~Input();
void getCursorPos(Common::Point& p) {
p = _mousePos;
@@ -116,7 +106,7 @@ public:
InventoryItem _activeItem;
void readInput();
- InputData* updateInput();
+ int updateInput();
void trackMouse(ZonePtr z);
void waitForButtonEvent(uint32 buttonEventMask, int32 timeout = -1);
uint32 getLastButtonEvent() { return _mouseButtons; }
@@ -129,6 +119,9 @@ public:
void setMouseState(MouseTriState state);
MouseTriState getMouseState();
bool isMouseEnabled();
+
+ void setArrowCursor();
+ void setInventoryCursor(ItemName name);
};
} // namespace Parallaction
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index c387484de7..b4776250c6 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -71,6 +71,20 @@ uint16 Animation::height() const {
return r.height();
}
+int16 Animation::getFrameX() const {
+ if (!gfxobj) return _left;
+ Common::Rect r;
+ gfxobj->getRect(_frame, r);
+ return r.left + _left;
+}
+
+int16 Animation::getFrameY() const {
+ if (!gfxobj) return _top;
+ Common::Rect r;
+ gfxobj->getRect(_frame, r);
+ return r.top + _top;
+}
+
uint16 Animation::getFrameNum() const {
if (!gfxobj) return 0;
return gfxobj->getNum();
@@ -115,24 +129,29 @@ int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) {
assert(_numLocals < NUM_LOCALS);
strcpy(_localNames[_numLocals], name);
- _locals[_numLocals]._value = value;
-
- _locals[_numLocals]._min = min;
- _locals[_numLocals]._max = max;
+ _locals[_numLocals].setRange(min, max);
+ _locals[_numLocals].setValue(value);
return _numLocals++;
}
-void LocalVariable::wrap() {
+void LocalVariable::setValue(int16 value) {
+ if (value >= _max)
+ value = _min;
+ if (value < _min)
+ value = _max - 1;
- if (_value >= _max)
- _value = _min;
- if (_value < _min)
- _value = _max - 1;
+ _value = value;
+}
- return;
+void LocalVariable::setRange(int16 min, int16 max) {
+ _max = max;
+ _min = min;
}
+int16 LocalVariable::getValue() const {
+ return _value;
+}
Zone::Zone() {
@@ -161,7 +180,6 @@ Zone::~Zone() {
case kZoneDoor:
free(u.door->_location);
- free(u.door->_background);
u.door->gfxobj->release();
delete u.door;
break;
@@ -172,7 +190,6 @@ Zone::~Zone() {
break;
case kZoneGet:
- free(u.get->_backup);
u.get->gfxobj->release();
delete u.get;
break;
@@ -193,13 +210,6 @@ Zone::~Zone() {
free(_linkedName);
}
-void Zone::getRect(Common::Rect& r) const {
- r.left = _left;
- r.right = _right;
- r.top = _top;
- r.bottom = _bottom;
-}
-
void Zone::translate(int16 x, int16 y) {
_left += x;
_right += x;
@@ -273,18 +283,18 @@ Instruction::~Instruction() {
free(_text2);
}
-int16 ScriptVar::getRValue() {
+int16 ScriptVar::getValue() {
if (_flags & kParaImmediate) {
return _value;
}
if (_flags & kParaLocal) {
- return _local->_value;
+ return _local->getValue();
}
if (_flags & kParaField) {
- return *_pvalue;
+ return _field->getValue();
}
if (_flags & kParaRandom) {
@@ -296,27 +306,33 @@ int16 ScriptVar::getRValue() {
return 0;
}
-int16* ScriptVar::getLValue() {
+void ScriptVar::setValue(int16 value) {
+ if ((_flags & kParaLValue) == 0) {
+ error("Only l-value can be set");
+ }
if (_flags & kParaLocal) {
- return &_local->_value;
+ _local->setValue(value);
}
if (_flags & kParaField) {
- return _pvalue;
+ _field->setValue(value);
}
- error("Parameter is not an l-value");
-
}
void ScriptVar::setLocal(LocalVariable *local) {
_local = local;
- _flags |= kParaLocal;
+ _flags |= (kParaLocal | kParaLValue);
}
-void ScriptVar::setField(int16 *field) {
- _pvalue = field;
+void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor, AnimationField::MutatorFunc mutator) {
+ _field = new AnimationField(anim, accessor, mutator);
+ _flags |= (kParaField | kParaLValue);
+}
+
+void ScriptVar::setField(Animation *anim, AnimationField::AccessorFunc accessor) {
+ _field = new AnimationField(anim, accessor);
_flags |= kParaField;
}
@@ -335,9 +351,14 @@ ScriptVar::ScriptVar() {
_flags = 0;
_local = 0;
_value = 0;
- _pvalue = 0;
+ _field = 0;
}
+ScriptVar::~ScriptVar() {
+ delete _field;
+}
+
+
Table::Table(uint32 size) : _size(size), _used(0), _disposeMemory(true) {
_data = (char**)calloc(size, sizeof(char*));
}
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index 7e7a811ba6..eee69383b6 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -192,20 +192,19 @@ struct Dialogue {
~Dialogue();
};
-struct GetData { // size = 24
+struct GetData {
uint32 _icon;
GfxObj *gfxobj;
- byte *_backup;
- uint16 field_14; // unused
- uint16 field_16; // unused
+ MaskBuffer _mask[2];
+ bool hasMask;
GetData() {
_icon = 0;
- _backup = NULL;
gfxobj = NULL;
+ hasMask = false;
}
};
-struct SpeakData { // size = 36
+struct SpeakData {
char _name[32];
Dialogue *_dialogue;
@@ -214,30 +213,25 @@ struct SpeakData { // size = 36
_dialogue = NULL;
}
};
-struct ExamineData { // size = 28
+struct ExamineData {
GfxObj *_cnv;
- uint16 _opBase; // unused
- uint16 field_12; // unused
char* _description;
char* _filename;
ExamineData() {
- _opBase = 0;
_description = NULL;
_filename = NULL;
_cnv = NULL;
}
};
-struct DoorData { // size = 28
+struct DoorData {
char* _location;
GfxObj *gfxobj;
- byte* _background;
Common::Point _startPos;
uint16 _startFrame;
DoorData() {
_location = NULL;
- _background = NULL;
_startFrame = 0;
gfxobj = NULL;
}
@@ -297,17 +291,19 @@ struct TypeData {
#define ZONENAME_LENGTH 32
struct Zone {
- char _name[ZONENAME_LENGTH];
-
+protected:
int16 _left;
int16 _top;
int16 _right;
int16 _bottom;
+
+public:
+ char _name[ZONENAME_LENGTH];
+
uint32 _type;
uint32 _flags;
uint _label;
- uint16 field_2C; // unused
- uint16 field_2E; // unused
+
TypeData u;
CommandList _commands;
Common::Point _moveTo;
@@ -320,32 +316,101 @@ struct Zone {
Zone();
virtual ~Zone();
- void getRect(Common::Rect& r) const;
void translate(int16 x, int16 y);
virtual uint16 width() const;
virtual uint16 height() const;
+
+ void setBox(int16 left, int16 top, int16 right, int16 bottom) {
+ setX(left);
+ setY(top);
+ _right = right;
+ _bottom = bottom;
+ }
+
+ void getBox(Common::Rect& r) {
+ r.left = getX();
+ r.right = getX() + width();
+ r.top = getY();
+ r.bottom = getY() + height();
+ }
+
+
+ // getters/setters
+ virtual int16 getX() { return _left; }
+ virtual void setX(int16 value) { _left = value; }
+
+ virtual int16 getY() { return _top; }
+ virtual void setY(int16 value) { _top = value; }
};
struct LocalVariable {
+protected:
int16 _value;
int16 _min;
int16 _max;
+public:
+
LocalVariable() {
_value = 0;
_min = -10000;
_max = 10000;
}
- void wrap();
+ void setRange(int16 min, int16 max);
+
+ int16 getValue() const;
+ void setValue(int16 value);
};
+
enum ParaFlags {
kParaImmediate = 1, // instruction is using an immediate parameter
kParaLocal = 2, // instruction is using a local variable
kParaField = 0x10, // instruction is using an animation's field
- kParaRandom = 0x100
+ kParaRandom = 0x100,
+
+ kParaLValue = 0x20
+};
+
+
+struct AnimationField {
+ typedef Common::Functor0Mem<int16, Animation> Accessor;
+ typedef Common::Functor1Mem<int16, void, Animation> Mutator;
+
+ typedef Accessor::FuncType AccessorFunc;
+ typedef Mutator::FuncType MutatorFunc;
+
+protected:
+ Accessor *_accessor;
+ Mutator *_mutator;
+
+public:
+ AnimationField(Animation* instance, AccessorFunc accessor, MutatorFunc mutator) {
+ _accessor = new Accessor(instance, accessor);
+ _mutator = new Mutator(instance, mutator);
+ }
+
+ AnimationField(Animation* instance, AccessorFunc accessor) {
+ _accessor = new Accessor(instance, accessor);
+ _mutator = 0;
+ }
+
+ ~AnimationField() {
+ delete _accessor;
+ delete _mutator;
+ }
+
+ int16 getValue() const {
+ assert(_accessor);
+ return _accessor->operator()();
+ }
+
+ void setValue(int16 value) {
+ assert(_mutator);
+ _mutator->operator()(value);
+ }
};
@@ -353,16 +418,18 @@ struct ScriptVar {
uint32 _flags;
int16 _value;
- int16* _pvalue;
LocalVariable* _local;
+ AnimationField* _field;
ScriptVar();
+ ~ScriptVar();
- int16 getRValue();
- int16* getLValue();
+ int16 getValue();
+ void setValue(int16 value);
void setLocal(LocalVariable *local);
- void setField(int16 *field);
+ void setField(Animation *anim, AnimationField::AccessorFunc accessor, AnimationField::MutatorFunc mutator);
+ void setField(Animation *anim, AnimationField::AccessorFunc accessor);
void setImmediate(int16 value);
void setRandom(int16 seed);
};
@@ -430,19 +497,13 @@ typedef Common::SharedPtr<Program> ProgramPtr;
typedef Common::List<ProgramPtr> ProgramList;
struct Animation : public Zone {
+protected:
+ int16 _frame;
+ int16 _z;
+public:
- Common::Point _oldPos;
GfxObj *gfxobj;
char *_scriptName;
- int16 _frame;
- uint16 field_50; // unused
- int16 _z;
- uint16 field_54; // unused
- uint16 field_56; // unused
- uint16 field_58; // unused
- uint16 field_5A; // unused
- uint16 field_5C; // unused
- uint16 field_5E; // unused
Animation();
virtual ~Animation();
@@ -452,6 +513,22 @@ struct Animation : public Zone {
byte* getFrameData(uint32 index) const;
void validateScriptVars();
+
+ int16 getFrameX() const;
+ int16 getFrameY() const;
+
+ // getters/setters used by scripts
+ int16 getX() { return _left; }
+ void setX(int16 value) { _left = value; }
+
+ int16 getY() { return _top; }
+ void setY(int16 value) { _top = value; }
+
+ int16 getZ() { return _z; }
+ void setZ(int16 value) { _z = value; }
+
+ int16 getF() { return _frame; }
+ void setF(int16 value) { _frame = value; }
};
class Table {
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index 54cb175e46..828cb4d021 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -35,6 +35,7 @@
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
#include "parallaction/debug.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
@@ -47,13 +48,12 @@ Parallaction *_vm = NULL;
// public stuff
char _saveData1[30] = { '\0' };
-uint16 _language = 0;
uint32 _engineFlags = 0;
uint16 _score = 1;
char _password[8];
-uint32 _commandFlags = 0;
+uint32 _globalFlags = 0;
// private stuff
@@ -66,7 +66,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
// FIXME
_vm = this;
- Common::File::addDefaultDirectory( _gameDataPath );
+ Common::File::addDefaultDirectory(_gameDataDir);
Common::addSpecialDebugLevel(kDebugDialogue, "dialogue", "Dialogues debug level");
Common::addSpecialDebugLevel(kDebugParser, "parser", "Parser debug level");
@@ -85,7 +85,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
Parallaction::~Parallaction() {
delete _debugger;
- delete _globalTable;
+ delete _globalFlagsNames;
delete _callableNames;
delete _cmdExec;
delete _programExec;
@@ -100,8 +100,6 @@ Parallaction::~Parallaction() {
cleanupGui();
- delete _comboArrow;
-
delete _localFlagNames;
delete _gfx;
delete _soundMan;
@@ -114,9 +112,8 @@ int Parallaction::init() {
_engineFlags = 0;
_objectsNames = NULL;
- _globalTable = NULL;
+ _globalFlagsNames = NULL;
_location._hasSound = false;
- _baseTime = 0;
_numLocations = 0;
_location._startPosition.x = -1000;
_location._startPosition.y = -1000;
@@ -124,6 +121,8 @@ int Parallaction::init() {
_location._comment = NULL;
_location._endComment = NULL;
+ _quit = false;
+
_pathBuffer = 0;
_screenSize = _screenWidth * _screenHeight;
@@ -134,6 +133,7 @@ int Parallaction::init() {
initInventory(); // needs to be pushed into subclass
+ // this needs _disk to be already setup
_input = new Input(this);
_gfx = new Gfx(this);
@@ -147,14 +147,6 @@ int Parallaction::init() {
return 0;
}
-
-void Parallaction::clearSet(OpcodeSet &opcodes) {
- for (Common::Array<const Opcode*>::iterator i = opcodes.begin(); i != opcodes.end(); ++i)
- delete *i;
- opcodes.clear();
-}
-
-
void Parallaction::updateView() {
if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) {
@@ -163,7 +155,7 @@ void Parallaction::updateView() {
_gfx->animatePalette();
_gfx->updateScreen();
- g_system->delayMillis(30);
+ _vm->_system->delayMillis(30);
}
@@ -264,7 +256,6 @@ void Parallaction::freeLocation() {
_location._walkPoints.clear();
_gfx->clearGfxObjects(kGfxObjNormal);
- freeBackground();
_location._programs.clear();
freeZones();
@@ -279,20 +270,30 @@ void Parallaction::freeLocation() {
return;
}
+void Parallaction::showSlide(const char *name, int x, int y) {
+ BackgroundInfo *info = new BackgroundInfo;
+ _disk->loadSlide(*info, name);
+
+ info->x = (x == CENTER_LABEL_HORIZONTAL) ? ((_vm->_screenWidth - info->width) >> 1) : x;
+ info->y = (y == CENTER_LABEL_VERTICAL) ? ((_vm->_screenHeight - info->height) >> 1) : y;
+ _gfx->setBackground(kBackgroundSlide, info);
+}
void Parallaction::freeBackground() {
- _gfx->freeBackground();
_pathBuffer = 0;
}
void Parallaction::setBackground(const char* name, const char* mask, const char* path) {
- _gfx->setBackground(kBackgroundLocation, name, mask, path);
- _pathBuffer = &_gfx->_backgroundInfo.path;
+ BackgroundInfo *info = new BackgroundInfo;
+ _disk->loadScenery(*info, name, mask, path);
+
+ _gfx->setBackground(kBackgroundLocation, info);
+ _pathBuffer = &info->path;
return;
}
@@ -302,22 +303,19 @@ void Parallaction::showLocationComment(const char *text, bool end) {
}
-void Parallaction::processInput(InputData *data) {
- if (!data) {
- return;
- }
+void Parallaction::processInput(int event) {
- switch (data->_event) {
+ switch (event) {
case kEvSaveGame:
_input->stopHovering();
- saveGame();
- setArrowCursor();
+ _saveLoad->saveGame();
+ _input->setArrowCursor();
break;
case kEvLoadGame:
_input->stopHovering();
- loadGame();
- setArrowCursor();
+ _saveLoad->loadGame();
+ _input->setArrowCursor();
break;
}
@@ -327,8 +325,8 @@ void Parallaction::processInput(InputData *data) {
void Parallaction::runGame() {
- InputData *data = _input->updateInput();
- if (_engineFlags & kEngineQuit)
+ int event = _input->updateInput();
+ if (quit())
return;
runGuiFrame();
@@ -336,10 +334,10 @@ void Parallaction::runGame() {
runCommentFrame();
if (_input->_inputMode == Input::kInputModeGame) {
- processInput(data);
+ processInput(event);
runPendingZones();
- if (_engineFlags & kEngineQuit)
+ if (quit())
return;
if (_engineFlags & kEngineChangeLocation) {
@@ -351,9 +349,9 @@ void Parallaction::runGame() {
if (_input->_inputMode == Input::kInputModeGame) {
_programExec->runScripts(_location._programs.begin(), _location._programs.end());
- _char._ani->_z = _char._ani->height() + _char._ani->_top;
+ _char._ani->setZ(_char._ani->height() + _char._ani->getFrameY());
if (_char._ani->gfxobj) {
- _char._ani->gfxobj->z = _char._ani->_z;
+ _char._ani->gfxobj->z = _char._ani->getZ();
}
_char._walker->walk();
drawAnimations();
@@ -402,7 +400,7 @@ void Parallaction::doLocationEnterTransition() {
pal.fadeTo(_gfx->_palette, 4);
_gfx->setPalette(pal);
_gfx->updateScreen();
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
}
_gfx->setPalette(_gfx->_palette);
@@ -430,6 +428,387 @@ uint32 Parallaction::getLocationFlags() {
+void Parallaction::drawAnimations() {
+ debugC(9, kDebugExec, "Parallaction_ns::drawAnimations()\n");
+
+ uint16 layer = 0, scale = 100;
+
+ for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) {
+
+ AnimationPtr anim = *it;
+ GfxObj *obj = anim->gfxobj;
+
+ // Validation is performed here, so that every animation is affected, instead that only the ones
+ // who *own* a script. In fact, some scripts can change values in other animations.
+ // The right way to do this would be to enforce validation when any variable is modified from
+ // a script.
+ anim->validateScriptVars();
+
+ if ((anim->_flags & kFlagsActive) && ((anim->_flags & kFlagsRemove) == 0)) {
+
+ if (anim->_flags & kFlagsNoMasked)
+ layer = LAYER_FOREGROUND;
+ else {
+ if (getGameType() == GType_Nippon) {
+ // Layer in NS depends on where the animation is on the screen, for each animation.
+ layer = _gfx->_backgroundInfo->getLayer(anim->getFrameY() + anim->height());
+ } else {
+ // Layer in BRA is calculated from Z value. For characters it is the same as NS,
+ // but other animations can have Z set from scripts independently from their
+ // position on the screen.
+ layer = _gfx->_backgroundInfo->getLayer(anim->getZ());
+ }
+ }
+
+ if (getGameType() == GType_BRA) {
+ if (anim->_flags & (kFlagsScaled | kFlagsCharacter)) {
+ if (anim->getZ() <= _location._zeta0) {
+ if (anim->getZ() >= _location._zeta1) {
+ scale = ((anim->getZ() - _location._zeta1) * (100 - _location._zeta2)) / (_location._zeta0 - _location._zeta1) + _location._zeta2;
+ } else {
+ scale = _location._zeta2;
+ }
+ }
+ }
+ }
+
+ if (obj) {
+ _gfx->showGfxObj(obj, true);
+ obj->frame = anim->getF();
+ obj->x = anim->getX();
+ obj->y = anim->getY();
+ obj->z = anim->getZ();
+ obj->layer = layer;
+ obj->scale = scale;
+ }
+ }
+
+ if (((anim->_flags & kFlagsActive) == 0) && (anim->_flags & kFlagsRemove)) {
+ anim->_flags &= ~kFlagsRemove;
+ }
+
+ if ((anim->_flags & kFlagsActive) && (anim->_flags & kFlagsRemove)) {
+ anim->_flags &= ~kFlagsActive;
+ anim->_flags |= kFlagsRemove;
+ if (obj) {
+ _gfx->showGfxObj(obj, false);
+ }
+ }
+ }
+
+ debugC(9, kDebugExec, "Parallaction_ns::drawAnimations done()\n");
+
+ return;
+}
+
+
+void Parallaction::showZone(ZonePtr z, bool visible) {
+ if (!z) {
+ return;
+ }
+
+ if (visible) {
+ z->_flags &= ~kFlagsRemove;
+ z->_flags |= kFlagsActive;
+ } else {
+ z->_flags |= kFlagsRemove;
+ }
+
+ if ((z->_type & 0xFFFF) == kZoneGet) {
+ _gfx->showGfxObj(z->u.get->gfxobj, visible);
+
+ GetData *data = z->u.get;
+ if (data->hasMask && _gfx->_backgroundInfo->hasMask) {
+ if (visible) {
+ _gfx->_backgroundInfo->mask.bltOr(data->gfxobj->x, data->gfxobj->y, data->_mask[0], 0, 0, data->_mask->w, data->_mask->h);
+ } else {
+ _gfx->_backgroundInfo->mask.bltCopy(data->gfxobj->x, data->gfxobj->y, data->_mask[1], 0, 0, data->_mask->w, data->_mask->h);
+ }
+ }
+ }
+}
+
+
+//
+// ZONE TYPE: EXAMINE
+//
+
+void Parallaction::enterCommentMode(ZonePtr z) {
+ if (!z) {
+ return;
+ }
+
+ _commentZone = z;
+
+ ExamineData *data = _commentZone->u.examine;
+
+ if (!data->_description) {
+ return;
+ }
+
+ // TODO: move this balloons stuff into DialogueManager and BalloonManager
+ if (getGameType() == GType_Nippon) {
+ int id;
+ if (data->_filename) {
+ if (data->_cnv == 0) {
+ data->_cnv = _disk->loadStatic(data->_filename);
+ }
+
+ _gfx->setHalfbriteMode(true);
+ _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, BalloonManager::kNormalColor);
+ Common::Rect r;
+ data->_cnv->getRect(0, r);
+ id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2);
+ _gfx->setItemFrame(id, 0);
+ id = _gfx->setItem(_char._head, 100, 152);
+ _gfx->setItemFrame(id, 0);
+ } else {
+ _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, BalloonManager::kNormalColor);
+ id = _gfx->setItem(_char._talk, 190, 80);
+ _gfx->setItemFrame(id, 0);
+ }
+ } else
+ if (getGameType() == GType_BRA) {
+ _balloonMan->setSingleBalloon(data->_description, 0, 0, 1, BalloonManager::kNormalColor);
+ int id = _gfx->setItem(_char._talk, 10, 80);
+ _gfx->setItemFrame(id, 0);
+ }
+
+ _input->_inputMode = Input::kInputModeComment;
+}
+
+void Parallaction::exitCommentMode() {
+ _input->_inputMode = Input::kInputModeGame;
+
+ hideDialogueStuff();
+ _gfx->setHalfbriteMode(false);
+
+ _cmdExec->run(_commentZone->_commands, _commentZone);
+ _commentZone = nullZonePtr;
+}
+
+void Parallaction::runCommentFrame() {
+ if (_input->_inputMode != Input::kInputModeComment) {
+ return;
+ }
+
+ if (_input->getLastButtonEvent() == kMouseLeftUp) {
+ exitCommentMode();
+ }
+}
+
+
+void Parallaction::runZone(ZonePtr z) {
+ debugC(3, kDebugExec, "runZone (%s)", z->_name);
+
+ uint16 subtype = z->_type & 0xFFFF;
+
+ debugC(3, kDebugExec, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16);
+ switch(subtype) {
+
+ case kZoneExamine:
+ enterCommentMode(z);
+ return;
+
+ case kZoneGet:
+ pickupItem(z);
+ break;
+
+ case kZoneDoor:
+ if (z->_flags & kFlagsLocked) break;
+ updateDoor(z, !(z->_flags & kFlagsClosed));
+ break;
+
+ case kZoneHear:
+ _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60);
+ break;
+
+ case kZoneSpeak:
+ enterDialogueMode(z);
+ return;
+ }
+
+ debugC(3, kDebugExec, "runZone completed");
+
+ _cmdExec->run(z->_commands, z);
+
+ return;
+}
+
+//
+// ZONE TYPE: DOOR
+//
+void Parallaction::updateDoor(ZonePtr z, bool close) {
+ z->_flags = close ? (z->_flags |= kFlagsClosed) : (z->_flags &= ~kFlagsClosed);
+
+ if (z->u.door->gfxobj) {
+ uint frame = (close ? 0 : 1);
+// z->u.door->gfxobj->setFrame(frame);
+ z->u.door->gfxobj->frame = frame;
+ }
+
+ return;
+}
+
+
+
+//
+// ZONE TYPE: GET
+//
+
+bool Parallaction::pickupItem(ZonePtr z) {
+ if (z->_flags & kFlagsFixed) {
+ return false;
+ }
+
+ int slot = addInventoryItem(z->u.get->_icon);
+ if (slot != -1) {
+ showZone(z, false);
+ }
+
+ return (slot != -1);
+}
+
+// FIXME: input coordinates must be offseted to handle scrolling!
+bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
+ // not a special zone
+ if ((z->getX() != -2) && (z->getX() != -3)) {
+ return false;
+ }
+
+ // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs
+ // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine,
+ // but we need to check it separately here. The same workaround is applied in freeZones.
+ if ((((z->_type & 0xFFFF) == kZoneMerge) && (((x == z->u.merge->_obj1) && (y == z->u.merge->_obj2)) || ((x == z->u.merge->_obj2) && (y == z->u.merge->_obj1)))) ||
+ (((z->_type & 0xFFFF) == kZoneGet) && ((x == z->u.get->_icon) || (y == z->u.get->_icon)))) {
+
+ // WORKAROUND for bug 2070751: special zones are only used in NS, to allow the
+ // the EXAMINE/USE action to be applied on some particular item in the inventory.
+ // The usage a verb requires at least an item match, so type can't be 0, as it
+ // was in the original code. This bug has been here since the beginning, and was
+ // hidden by label code, which filtered the bogus matches produced here.
+
+ // look for action + item match
+ if (z->_type == type)
+ return true;
+ // look for item match, but don't accept 0 types
+ if (((z->_type & 0xFFFF0000) == type) && (type))
+ return true;
+ }
+
+ return false;
+}
+
+// FIXME: input coordinates must be offseted to handle scrolling!
+bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
+ if (z->_flags & kFlagsRemove)
+ return false;
+
+ debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y);
+
+ Common::Rect r;
+ z->getBox(r);
+ r.right++; // adjust border because Common::Rect doesn't include bottom-right edge
+ r.bottom++;
+
+ r.grow(-1); // allows some tolerance for mouse click
+
+ if (!r.contains(x, y)) {
+
+ // check for special zones (items defined in common.loc)
+ if (checkSpecialZoneBox(z, type, x, y))
+ return true;
+
+ if (z->getX() != -1)
+ return false;
+ if ((int)x < _char._ani->getFrameX())
+ return false;
+ if ((int)x > (_char._ani->getFrameX() + _char._ani->width()))
+ return false;
+ if ((int)y < _char._ani->getFrameY())
+ return false;
+ if ((int)y > (_char._ani->getFrameY() + _char._ani->height()))
+ return false;
+ }
+
+ // normal Zone
+ if ((type == 0) && ((z->_type & 0xFFFF0000) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if ((z->_type & 0xFFFF0000) == type)
+ return true;
+
+ return false;
+}
+
+// FIXME: input coordinates must be offseted to handle scrolling!
+bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
+ if (z->_flags & kFlagsRemove)
+ return false;
+
+ if ((z->_flags & kFlagsAnimLinked) == 0)
+ return false;
+
+ debugC(5, kDebugExec, "checkLinkedAnimBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y);
+
+ AnimationPtr anim = z->_linkedAnim;
+ Common::Rect r(anim->getFrameX(), anim->getFrameY(), anim->getFrameX() + anim->width() + 1, anim->getFrameY() + anim->height() + 1);
+
+ if (!r.contains(x, y)) {
+ return false;
+ }
+
+ // NOTE: the implementation of the following lines is a different in the
+ // original... it is working so far, though
+ if ((type == 0) && ((z->_type & 0xFFFF0000) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if ((z->_type & 0xFFFF0000) == type)
+ return true;
+
+ return false;
+}
+
+ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
+ uint16 _di = y;
+ uint16 _si = x;
+
+ for (ZoneList::iterator it = _location._zones.begin(); it != _location._zones.end(); it++) {
+ if (checkLinkedAnimBox(*it, type, x, y)) {
+ return *it;
+ }
+ if (checkZoneBox(*it, type, x, y)) {
+ return *it;
+ }
+ }
+
+
+ int16 _a, _b, _c, _d, _e, _f;
+ for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ait++) {
+
+ AnimationPtr a = *ait;
+
+ _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
+ _e = ((_si >= a->getFrameX() + a->width()) || (_si <= a->getFrameX())) ? 0 : 1; // _e: horizontal range
+ _f = ((_di >= a->getFrameY() + a->height()) || (_di <= a->getFrameY())) ? 0 : 1; // _f: vertical range
+
+ _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
+ _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object
+ _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type
+
+ if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) {
+
+ return a;
+
+ }
+
+ }
+
+ return nullZonePtr;
+}
+
ZonePtr Parallaction::findZone(const char *name) {
@@ -442,7 +821,7 @@ ZonePtr Parallaction::findZone(const char *name) {
void Parallaction::freeZones() {
- debugC(2, kDebugExec, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit);
+ debugC(2, kDebugExec, "freeZones: _vm->_quit = %i", _vm->_quit);
ZoneList::iterator it = _location._zones.begin();
@@ -451,7 +830,7 @@ void Parallaction::freeZones() {
// NOTE : this condition has been relaxed compared to the original, to allow the engine
// to retain special - needed - zones that were lost across location switches.
ZonePtr z = *it;
- if (((z->_top == -1) || (z->_left == -2)) && ((_engineFlags & kEngineQuit) == 0)) {
+ if (((z->getY() == -1) || (z->getX() == -2)) && (_quit == 0)) {
debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name);
it++;
} else {
@@ -509,13 +888,11 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation) {
_dummy = false;
- _ani->_left = 150;
- _ani->_top = 100;
- _ani->_z = 10;
- _ani->_oldPos.x = -1000;
- _ani->_oldPos.y = -1000;
- _ani->_frame = 0;
- _ani->_flags = kFlagsActive | kFlagsNoName;
+ _ani->setX(150);
+ _ani->setY(100);
+ _ani->setZ(10);
+ _ani->setF(0);
+ _ani->_flags = kFlagsActive | kFlagsNoName | kFlagsCharacter;
_ani->_type = kZoneYou;
strncpy(_ani->_name, "yourself", ZONENAME_LENGTH);
@@ -541,18 +918,18 @@ Character::~Character() {
void Character::getFoot(Common::Point &foot) {
Common::Rect rect;
- _ani->gfxobj->getRect(_ani->_frame, rect);
+ _ani->gfxobj->getRect(_ani->getF(), rect);
- foot.x = _ani->_left + (rect.left + rect.width() / 2);
- foot.y = _ani->_top + (rect.top + rect.height());
+ foot.x = _ani->getX() + (rect.left + rect.width() / 2);
+ foot.y = _ani->getY() + (rect.top + rect.height());
}
void Character::setFoot(const Common::Point &foot) {
Common::Rect rect;
- _ani->gfxobj->getRect(_ani->_frame, rect);
+ _ani->gfxobj->getRect(_ani->getF(), rect);
- _ani->_left = foot.x - (rect.left + rect.width() / 2);
- _ani->_top = foot.y - (rect.top + rect.height());
+ _ani->setX(foot.x - (rect.left + rect.width() / 2));
+ _ani->setY(foot.y - (rect.top + rect.height()));
}
#if 0
@@ -676,7 +1053,7 @@ void Character::updateDirection(const Common::Point& pos, const Common::Point& t
_step++;
if (dist.x == 0 && dist.y == 0) {
- _ani->_frame = frames->stillFrame[_direction];
+ _ani->setF(frames->stillFrame[_direction]);
return;
}
@@ -686,7 +1063,7 @@ void Character::updateDirection(const Common::Point& pos, const Common::Point& t
dist.y = -dist.y;
_direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP);
- _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction];
+ _ani->setF(frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction]);
}
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index d8e4da5baf..d7add635cd 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -29,6 +29,7 @@
#include "common/str.h"
#include "common/stack.h"
#include "common/array.h"
+#include "common/func.h"
#include "common/savefile.h"
#include "engines/engine.h"
@@ -44,8 +45,6 @@
#define PATH_LEN 200
-extern OSystem *g_system;
-
namespace Parallaction {
enum {
@@ -71,35 +70,7 @@ enum {
};
-// high values mean high priority
-
-enum {
- kPriority0 = 0,
- kPriority1 = 1,
- kPriority2 = 2,
- kPriority3 = 3,
- kPriority4 = 4,
- kPriority5 = 5,
- kPriority6 = 6,
- kPriority7 = 7,
- kPriority8 = 8,
- kPriority9 = 9,
- kPriority10 = 10,
- kPriority11 = 11,
- kPriority12 = 12,
- kPriority13 = 13,
- kPriority14 = 14,
- kPriority15 = 15,
- kPriority16 = 16,
- kPriority17 = 17,
- kPriority18 = 18,
- kPriority19 = 19,
- kPriority20 = 20,
- kPriority21 = 21
-};
-
enum EngineFlags {
- kEngineQuit = (1 << 0),
kEnginePauseJobs = (1 << 1),
kEngineWalking = (1 << 3),
kEngineChangeLocation = (1 << 4),
@@ -116,10 +87,6 @@ enum {
kEvLoadGame = 4000
};
-enum {
- kCursorArrow = -1
-};
-
enum ParallactionGameType {
GType_Nippon = 1,
GType_BRA
@@ -130,13 +97,11 @@ struct PARALLACTIONGameDescription;
-extern uint16 _mouseButtons;
extern char _password[8];
extern uint16 _score;
-extern uint16 _language;
extern uint32 _engineFlags;
extern char _saveData1[];
-extern uint32 _commandFlags;
+extern uint32 _globalFlags;
extern const char *_dinoName;
extern const char *_donnaName;
extern const char *_doughName;
@@ -238,6 +203,7 @@ public:
};
+class SaveLoad;
#define NUM_LOCATIONS 120
@@ -245,229 +211,148 @@ class Parallaction : public Engine {
friend class Debugger;
public:
-
- Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc);
- ~Parallaction();
-
- int init();
-
- virtual bool loadGame() = 0;
- virtual bool saveGame() = 0;
-
- Input *_input;
-
- void processInput(InputData* data);
-
- void pauseJobs();
- void resumeJobs();
-
- ZonePtr findZone(const char *name);
- ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
- uint16 runZone(ZonePtr z);
- void freeZones();
-
- AnimationPtr findAnimation(const char *name);
- void freeAnimations();
-
- void setBackground(const char *background, const char *mask, const char *path);
- void freeBackground();
-
- Table *_globalTable;
- Table *_objectsNames;
- Table *_callableNames;
- Table *_localFlagNames;
-
-public:
int getGameType() const;
uint32 getFeatures() const;
Common::Language getLanguage() const;
Common::Platform getPlatform() const;
+protected: // members
+ bool detectGame(void);
+
private:
const PARALLACTIONGameDescription *_gameDescription;
+ uint16 _language;
public:
+ Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc);
+ ~Parallaction();
+
+ int init();
+
// info
int32 _screenWidth;
int32 _screenHeight;
int32 _screenSize;
- PathBuffer *_pathBuffer;
-
+ // subsystems
+ Gfx *_gfx;
+ Disk *_disk;
+ Input *_input;
SoundMan *_soundMan;
+ Debugger *_debugger;
+ SaveLoad *_saveLoad;
+ MenuInputHelper *_menuHelper;
+ Common::RandomSource _rnd;
- Gfx* _gfx;
- Disk* _disk;
+ // fonts
+ Font *_labelFont;
+ Font *_menuFont;
+ Font *_introFont;
+ Font *_dialogueFont;
- CommandExec* _cmdExec;
- ProgramExec* _programExec;
+ // game utilities
+ Table *_globalFlagsNames;
+ Table *_objectsNames;
+ Table *_callableNames;
+ Table *_localFlagNames;
+ CommandExec *_cmdExec;
+ ProgramExec *_programExec;
+ PathBuffer *_pathBuffer;
+ Inventory *_inventory;
+ BalloonManager *_balloonMan;
+ DialogueManager *_dialogueMan;
+ InventoryRenderer *_inventoryRenderer;
+
+ // game data
Character _char;
-
- void setLocationFlags(uint32 flags);
- void clearLocationFlags(uint32 flags);
- void toggleLocationFlags(uint32 flags);
- uint32 getLocationFlags();
-
uint32 _localFlags[NUM_LOCATIONS];
char _locationNames[NUM_LOCATIONS][32];
int16 _currentLocationIndex;
uint16 _numLocations;
Location _location;
-
ZonePtr _activeZone;
+ char _characterName1[50]; // only used in changeCharacter
+ ZonePtr _zoneTrap;
+ ZonePtr _commentZone;
+ bool _quit; /* The only reason this flag exists is for freeZones() to properly
+ * delete all zones when necessary. THIS FLAG IS NOT THE ENGINE QUIT FLAG,
+ * use _eventMan->shouldQuit() for that.
+ */
- Font *_labelFont;
- Font *_menuFont;
- Font *_introFont;
- Font *_dialogueFont;
-
- Common::RandomSource _rnd;
-
- Debugger *_debugger;
- Frames *_comboArrow;
-
-
-protected: // data
- uint32 _baseTime;
- char _characterName1[50]; // only used in changeCharacter
-
- Common::String _saveFileName;
-
-
-protected: // members
- bool detectGame(void);
-
- void initGlobals();
- void runGame();
- void updateView();
-
- void doLocationEnterTransition();
- virtual void changeLocation(char *location) = 0;
- virtual void runPendingZones() = 0;
- void allocateLocationSlot(const char *name);
- void finalizeLocationParsing();
- void freeLocation();
- void showLocationComment(const char *text, bool end);
-
- void displayComment(ExamineData *data);
-
- void freeCharacter();
-
- int16 pickupItem(ZonePtr z);
-
- void clearSet(OpcodeSet &opcodes);
-
+protected:
+ void runGame();
+ void runGuiFrame();
+ void cleanupGui();
+ void runDialogueFrame();
+ void exitDialogueMode();
+ void runCommentFrame();
+ void enterCommentMode(ZonePtr z);
+ void exitCommentMode();
+ void processInput(int event);
+ void updateView();
+ void drawAnimations();
+ void freeCharacter();
+ void freeLocation();
+ void doLocationEnterTransition();
+ void allocateLocationSlot(const char *name);
+ void finalizeLocationParsing();
+ void showLocationComment(const char *text, bool end);
+ void setupBalloonManager();
public:
- void scheduleLocationSwitch(const char *location);
- virtual void changeCharacter(const char *name) = 0;
-
- virtual void callFunction(uint index, void* parm) { }
-
- virtual void setArrowCursor() = 0;
- virtual void setInventoryCursor(ItemName name) = 0;
-
- virtual void parseLocation(const char* name) = 0;
-
- void updateDoor(ZonePtr z);
-
- virtual void drawAnimations() = 0;
-
- void beep();
-
- ZonePtr _zoneTrap;
- PathBuilder* getPathBuilder(Character *ch);
+ void beep();
+ void pauseJobs();
+ void resumeJobs();
+ void hideDialogueStuff();
+ uint getInternLanguage();
+ void setInternLanguage(uint id);
+ void enterDialogueMode(ZonePtr z);
+ void scheduleLocationSwitch(const char *location);
+ void showSlide(const char *name, int x = 0, int y = 0);
public:
-// const char **_zoneFlagNamesRes;
-// const char **_zoneTypeNamesRes;
-// const char **_commandsNamesRes;
- const char **_callableNamesRes;
- const char **_instructionNamesRes;
-
- void highlightInventoryItem(ItemPosition pos);
- int16 getHoverInventoryItem(int16 x, int16 y);
- int addInventoryItem(ItemName item);
- int addInventoryItem(ItemName item, uint32 value);
- void dropItem(uint16 v);
- bool isItemInInventory(int32 v);
- const InventoryItem* getInventoryItem(int16 pos);
- int16 getInventoryItemIndex(int16 pos);
- void initInventory();
- void destroyInventory();
- void cleanInventory(bool keepVerbs = true);
- void openInventory();
- void closeInventory();
-
- Inventory *_inventory;
- InventoryRenderer *_inventoryRenderer;
-
- BalloonManager *_balloonMan;
-
- void setupBalloonManager();
-
- void hideDialogueStuff();
- DialogueManager *_dialogueMan;
- void enterDialogueMode(ZonePtr z);
- void exitDialogueMode();
- void runDialogueFrame();
-
- MenuInputHelper *_menuHelper;
- void runGuiFrame();
- void cleanupGui();
-
- ZonePtr _commentZone;
- void enterCommentMode(ZonePtr z);
- void exitCommentMode();
- void runCommentFrame();
+ void setLocationFlags(uint32 flags);
+ void clearLocationFlags(uint32 flags);
+ void toggleLocationFlags(uint32 flags);
+ uint32 getLocationFlags();
+ bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y);
+ bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y);
+ bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y);
+ ZonePtr findZone(const char *name);
+ ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
+ void runZone(ZonePtr z);
+ void freeZones();
+ bool pickupItem(ZonePtr z);
+ void updateDoor(ZonePtr z, bool close);
+ void showZone(ZonePtr z, bool visible);
+ AnimationPtr findAnimation(const char *name);
+ void freeAnimations();
+ void setBackground(const char *background, const char *mask, const char *path);
+ void freeBackground();
+ void highlightInventoryItem(ItemPosition pos);
+ int16 getHoverInventoryItem(int16 x, int16 y);
+ int addInventoryItem(ItemName item);
+ int addInventoryItem(ItemName item, uint32 value);
+ void dropItem(uint16 v);
+ bool isItemInInventory(int32 v);
+ const InventoryItem* getInventoryItem(int16 pos);
+ int16 getInventoryItemIndex(int16 pos);
+ void initInventory();
+ void destroyInventory();
+ void cleanInventory(bool keepVerbs = true);
+ void openInventory();
+ void closeInventory();
- void setInternLanguage(uint id);
- uint getInternLanguage();
+ virtual void parseLocation(const char* name) = 0;
+ virtual void changeLocation(char *location) = 0;
+ virtual void changeCharacter(const char *name) = 0;
+ virtual void callFunction(uint index, void* parm) = 0;
+ virtual void runPendingZones() = 0;
+ virtual void cleanupGame() = 0;
};
-class LocationName {
-
- Common::String _slide;
- Common::String _character;
- Common::String _location;
-
- bool _hasCharacter;
- bool _hasSlide;
- char *_buf;
-
-public:
- LocationName();
- ~LocationName();
-
- void bind(const char*);
-
- const char *location() const {
- return _location.c_str();
- }
-
- bool hasCharacter() const {
- return _hasCharacter;
- }
-
- const char *character() const {
- return _character.c_str();
- }
-
- bool hasSlide() const {
- return _hasSlide;
- }
-
- const char *slide() const {
- return _slide.c_str();
- }
-
- const char *c_str() const {
- return _buf;
- }
-};
-
class Parallaction_ns : public Parallaction {
@@ -479,70 +364,45 @@ public:
int go();
public:
- typedef void (Parallaction_ns::*Callable)(void*);
-
- virtual void callFunction(uint index, void* parm);
+ virtual void parseLocation(const char *filename);
+ virtual void changeLocation(char *location);
+ virtual void changeCharacter(const char *name);
+ virtual void callFunction(uint index, void* parm);
+ virtual void runPendingZones();
+ virtual void cleanupGame();
- bool loadGame();
- bool saveGame();
- void switchBackground(const char* background, const char* mask);
- void showSlide(const char *name);
- void setArrowCursor();
-
- // TODO: this should be private!!!!!!!
- bool _inTestResult;
- void cleanupGame();
- bool allPartsComplete();
+ void switchBackground(const char* background, const char* mask);
private:
- LocationParser_ns *_locationParser;
- ProgramParser_ns *_programParser;
-
- void initFonts();
- void freeFonts();
- void renameOldSavefiles();
- Common::String genSaveFileName(uint slot, bool oldStyle = false);
- Common::InSaveFile *getInSaveFile(uint slot);
- Common::OutSaveFile *getOutSaveFile(uint slot);
- void setPartComplete(const Character& character);
+ bool _inTestResult;
+ LocationParser_ns *_locationParser;
+ ProgramParser_ns *_programParser;
private:
- void changeLocation(char *location);
- void changeCharacter(const char *name);
- void runPendingZones();
+ void initFonts();
+ void freeFonts();
+ void initResources();
+ void startGui();
+ void startCreditSequence();
+ void startEndPartSequence();
+ void loadProgram(AnimationPtr a, const char *filename);
- void setInventoryCursor(ItemName name);
-
-
- void doLoadGame(uint16 slot);
- void doSaveGame(uint16 slot, const char* name);
- int buildSaveFileList(Common::StringList& l);
- int selectSaveFile(uint16 arg_0, const char* caption, const char* button);
-
- void initResources();
- void initCursors();
-
- static byte _resMouseArrow[256];
- byte *_mouseArrow;
-
- static const Callable _dosCallables[25];
- static const Callable _amigaCallables[25];
-
- /*
- game callables data members
- */
+ // callables data
+ typedef void (Parallaction_ns::*Callable)(void*);
+ const Callable *_callables;
ZonePtr _moveSarcZone0;
ZonePtr _moveSarcZone1;
uint16 num_foglie;
int16 _introSarcData1;
uint16 _introSarcData2; // sarcophagus stuff to be saved
uint16 _introSarcData3; // sarcophagus stuff to be saved
-
ZonePtr _moveSarcZones[5];
ZonePtr _moveSarcExaZones[5];
AnimationPtr _rightHandAnim;
+ static const Callable _dosCallables[25];
+ static const Callable _amigaCallables[25];
// common callables
void _c_play_boogie(void*);
@@ -576,20 +436,6 @@ private:
void _c_startMusic(void*);
void _c_closeMusic(void*);
void _c_HBOn(void*);
-
- const Callable *_callables;
-
-protected:
- void drawAnimations();
-
- void parseLocation(const char *filename);
- void loadProgram(AnimationPtr a, const char *filename);
-
- void selectStartLocation();
-
- void startGui();
- void startCreditSequence();
- void startEndPartSequence();
};
@@ -598,8 +444,6 @@ protected:
class Parallaction_br : public Parallaction_ns {
- typedef Parallaction_ns Super;
-
public:
Parallaction_br(OSystem* syst, const PARALLACTIONGameDescription *gameDesc) : Parallaction_ns(syst, gameDesc) { }
~Parallaction_br();
@@ -608,81 +452,55 @@ public:
int go();
public:
- typedef void (Parallaction_br::*Callable)(void*);
+ virtual void parseLocation(const char* name);
+ virtual void changeLocation(char *location);
+ virtual void changeCharacter(const char *name);
virtual void callFunction(uint index, void* parm);
- void changeCharacter(const char *name);
+ virtual void runPendingZones();
+ virtual void cleanupGame();
+
+
void setupSubtitles(char *s, char *s2, int y);
void clearSubtitles();
-
public:
Table *_countersNames;
-
const char **_audioCommandsNamesRes;
-
+ static const char *_partNames[];
int _part;
- int _progress;
-
+#if 0 // disabled since I couldn't find any references to lip sync in the scripts
int16 _lipSyncVal;
uint _subtitleLipSync;
+#endif
int _subtitleY;
int _subtitle[2];
-
ZonePtr _activeZone2;
-
int32 _counters[32];
-
uint32 _zoneFlags[NUM_LOCATIONS][NUM_ZONES];
- void startPart(uint part);
- void setArrowCursor();
+
private:
LocationParser_br *_locationParser;
ProgramParser_br *_programParser;
- void initResources();
- void initFonts();
- void freeFonts();
-
- void setInventoryCursor(ItemName name);
-
- void changeLocation(char *location);
- void runPendingZones();
-
- void initPart();
- void freePart();
-
- void initCursors();
-
- Frames *_dinoCursor;
- Frames *_dougCursor;
- Frames *_donnaCursor;
- Frames *_mouseArrow;
-
-
- static const char *_partNames[];
-
- void startGui();
+private:
+ void initResources();
+ void initFonts();
+ void freeFonts();
+ void freeLocation();
+ void loadProgram(AnimationPtr a, const char *filename);
+ void startGui(bool showSplash);
+ typedef void (Parallaction_br::*Callable)(void*);
+ const Callable *_callables;
static const Callable _dosCallables[6];
+ // dos callables
void _c_blufade(void*);
void _c_resetpalette(void*);
void _c_ferrcycle(void*);
void _c_lipsinc(void*);
void _c_albcycle(void*);
void _c_password(void*);
-
- const Callable *_callables;
-
- void parseLocation(const char* name);
- void loadProgram(AnimationPtr a, const char *filename);
-
-#if 0
- void jobWaitRemoveLabelJob(void *parm, Job *job);
- void jobPauseSfx(void *parm, Job *job);
- void jobStopFollower(void *parm, Job *job);
- void jobScroll(void *parm, Job *job);
-#endif
};
// FIXME: remove global
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 761c8d1b74..a06fba43f9 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -28,31 +28,11 @@
#include "parallaction/parallaction.h"
#include "parallaction/input.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
namespace Parallaction {
-struct MouseComboProperties {
- int _xOffset;
- int _yOffset;
- int _width;
- int _height;
-};
-/*
-// TODO: improve NS's handling of normal cursor before merging cursor code.
-MouseComboProperties _mouseComboProps_NS = {
- 7, // combo x offset (the icon from the inventory will be rendered from here)
- 7, // combo y offset (ditto)
- 32, // combo (arrow + icon) width
- 32 // combo (arrow + icon) height
-};
-*/
-MouseComboProperties _mouseComboProps_BR = {
- 8, // combo x offset (the icon from the inventory will be rendered from here)
- 8, // combo y offset (ditto)
- 68, // combo (arrow + icon) width
- 68 // combo (arrow + icon) height
-};
const char *Parallaction_br::_partNames[] = {
"PART0",
@@ -62,14 +42,6 @@ const char *Parallaction_br::_partNames[] = {
"PART4"
};
-const char *partFirstLocation[] = {
- "intro",
- "museo",
- "start",
- "bolscoi",
- "treno"
-};
-
int Parallaction_br::init() {
_screenWidth = 640;
@@ -96,7 +68,6 @@ int Parallaction_br::init() {
initResources();
initFonts();
- initCursors();
_locationParser = new LocationParser_br(this);
_locationParser->init();
_programParser = new ProgramParser_br(this);
@@ -112,6 +83,8 @@ int Parallaction_br::init() {
_subtitle[0] = -1;
_subtitle[1] = -1;
+ _saveLoad = new SaveLoad_br(this, _saveFileMan);
+
Parallaction::init();
return 0;
@@ -119,12 +92,6 @@ int Parallaction_br::init() {
Parallaction_br::~Parallaction_br() {
freeFonts();
-
- delete _dinoCursor;
- delete _dougCursor;
- delete _donnaCursor;
-
- delete _mouseArrow;
}
void Parallaction_br::callFunction(uint index, void* parm) {
@@ -135,25 +102,27 @@ void Parallaction_br::callFunction(uint index, void* parm) {
int Parallaction_br::go() {
- if (getFeatures() & GF_DEMO) {
- startPart(1);
- } else {
- startGui();
- }
+ bool splash = true;
+
+ while (!quit()) {
- while ((_engineFlags & kEngineQuit) == 0) {
+ if (getFeatures() & GF_DEMO) {
+ scheduleLocationSwitch("camalb.1");
+ _input->_inputMode = Input::kInputModeGame;
+ } else {
+ startGui(splash);
+ // don't show splash after first time
+ splash = false;
+ }
// initCharacter();
- _input->_inputMode = Input::kInputModeGame;
- while ((_engineFlags & (kEngineReturn | kEngineQuit)) == 0) {
+ while (((_engineFlags & kEngineReturn) == 0) && (!quit())) {
runGame();
}
_engineFlags &= ~kEngineReturn;
- freePart();
-// freeCharacter();
-
+ cleanupGame();
}
return 0;
@@ -169,70 +138,6 @@ void Parallaction_br::freeFonts() {
return;
}
-void Parallaction_br::initCursors() {
-
- if (getPlatform() == Common::kPlatformPC) {
- _dinoCursor = _disk->loadPointer("pointer1");
- _dougCursor = _disk->loadPointer("pointer2");
- _donnaCursor = _disk->loadPointer("pointer3");
-
- Graphics::Surface *surf = new Graphics::Surface;
- surf->create(_mouseComboProps_BR._width, _mouseComboProps_BR._height, 1);
- _comboArrow = new SurfaceToFrames(surf);
-
- // TODO: choose the pointer depending on the active character
- // For now, we pick Donna's
- _mouseArrow = _donnaCursor;
- } else {
- // TODO: Where are the Amiga cursors?
- }
-
-}
-
-void Parallaction_br::initPart() {
-
- memset(_counters, 0, ARRAYSIZE(_counters));
-
- _globalTable = _disk->loadTable("global");
- _objectsNames = _disk->loadTable("objects");
- _countersNames = _disk->loadTable("counters");
-
- // TODO: maybe handle this into Disk
- if (getPlatform() == Common::kPlatformPC) {
- _char._objs = _disk->loadObjects("icone.ico");
- } else {
- _char._objs = _disk->loadObjects("icons.ico");
- }
-
-}
-
-void Parallaction_br::freePart() {
-
- delete _globalTable;
- delete _objectsNames;
- delete _countersNames;
-
- _globalTable = 0;
- _objectsNames = 0;
- _countersNames = 0;
-}
-
-void Parallaction_br::startPart(uint part) {
- _part = part;
- _disk->selectArchive(_partNames[_part]);
-
- initPart();
-
- if (getFeatures() & GF_DEMO) {
- strcpy(_location._name, "camalb");
- } else {
- strcpy(_location._name, partFirstLocation[_part]);
- }
-
- parseLocation("common");
- changeLocation(_location._name);
-
-}
void Parallaction_br::runPendingZones() {
ZonePtr z;
@@ -260,8 +165,7 @@ void Parallaction_br::runPendingZones() {
}
}
-
-void Parallaction_br::changeLocation(char *location) {
+void Parallaction_br::freeLocation() {
// free open location stuff
clearSubtitles();
@@ -279,27 +183,75 @@ void Parallaction_br::changeLocation(char *location) {
_location._animations.push_front(_char._ani);
-// free(_location._comment);
-// _location._comment = 0;
+ free(_location._comment);
+ _location._comment = 0;
_location._commands.clear();
_location._aCommands.clear();
+}
+
+void Parallaction_br::cleanupGame() {
+ freeLocation();
+
+// freeCharacter();
+
+ delete _globalFlagsNames;
+ delete _objectsNames;
+ delete _countersNames;
+
+ _globalFlagsNames = 0;
+ _objectsNames = 0;
+ _countersNames = 0;
+}
+
+
+void Parallaction_br::changeLocation(char *location) {
+ char *partStr = strrchr(location, '.');
+ if (partStr) {
+ int n = partStr - location;
+ strncpy(_location._name, location, n);
+ _location._name[n] = '\0';
+
+ _part = atoi(++partStr);
+ if (getFeatures() & GF_DEMO) {
+ assert(_part == 1);
+ } else {
+ assert(_part >= 0 && _part <= 4);
+ }
+
+ _disk->selectArchive(_partNames[_part]);
+
+ memset(_counters, 0, ARRAYSIZE(_counters));
+
+ _globalFlagsNames = _disk->loadTable("global");
+ _objectsNames = _disk->loadTable("objects");
+ _countersNames = _disk->loadTable("counters");
+
+ // TODO: maybe handle this into Disk
+ if (getPlatform() == Common::kPlatformPC) {
+ _char._objs = _disk->loadObjects("icone.ico");
+ } else {
+ _char._objs = _disk->loadObjects("icons.ico");
+ }
+
+ parseLocation("common");
+ }
+
+ freeLocation();
// load new location
parseLocation(location);
-
- // kFlagsRemove is cleared because the character defaults to visible on new locations
- // script command can hide the character, anyway, so that's why the flag is cleared
- // before _location._commands are executed
+ // kFlagsRemove is cleared because the character is visible by default.
+ // Commands can hide the character, anyway.
_char._ani->_flags &= ~kFlagsRemove;
-
_cmdExec->run(_location._commands);
-// doLocationEnterTransition();
+
+ doLocationEnterTransition();
+
_cmdExec->run(_location._aCommands);
_engineFlags &= ~kEngineChangeLocation;
}
-
// FIXME: Parallaction_br::parseLocation() is now a verbatim copy of the same routine from Parallaction_ns.
void Parallaction_br::parseLocation(const char *filename) {
debugC(1, kDebugParser, "parseLocation('%s')", filename);
@@ -359,30 +311,5 @@ void Parallaction_br::changeCharacter(const char *name) {
}
-void Parallaction_br::setArrowCursor() {
- // FIXME: Where are the Amiga cursors?
- if (getPlatform() == Common::kPlatformAmiga)
- return;
-
- Common::Rect r;
- _mouseArrow->getRect(0, r);
-
- _system->setMouseCursor(_mouseArrow->getData(0), r.width(), r.height(), 0, 0, 0);
- _system->showMouse(true);
-
- _input->_activeItem._id = 0;
-}
-
-void Parallaction_br::setInventoryCursor(ItemName name) {
- assert(name > 0);
-
- byte *src = _mouseArrow->getData(0);
- byte *dst = _comboArrow->getData(0);
- memcpy(dst, src, _comboArrow->getSize(0));
-
- // FIXME: destination offseting is not clear
- _inventoryRenderer->drawItem(name, dst + _mouseComboProps_BR._yOffset * _mouseComboProps_BR._width + _mouseComboProps_BR._xOffset, _mouseComboProps_BR._width);
- _system->setMouseCursor(dst, _mouseComboProps_BR._width, _mouseComboProps_BR._height, 0, 0, 0);
-}
} // namespace Parallaction
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 851fe38138..8e11931c28 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -29,27 +29,61 @@
#include "parallaction/parallaction.h"
#include "parallaction/input.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
namespace Parallaction {
-#define MOUSEARROW_WIDTH 16
-#define MOUSEARROW_HEIGHT 16
+class LocationName {
-#define MOUSECOMBO_WIDTH 32 // sizes for cursor + selected inventory item
-#define MOUSECOMBO_HEIGHT 32
+ Common::String _slide;
+ Common::String _character;
+ Common::String _location;
-LocationName::LocationName() {
- _buf = 0;
- _hasSlide = false;
- _hasCharacter = false;
-}
+ bool _hasCharacter;
+ bool _hasSlide;
+ char *_buf;
+
+public:
+ LocationName() {
+ _buf = 0;
+ _hasSlide = false;
+ _hasCharacter = false;
+ }
+
+ ~LocationName() {
+ free(_buf);
+ }
+
+ void bind(const char*);
+
+ const char *location() const {
+ return _location.c_str();
+ }
+
+ bool hasCharacter() const {
+ return _hasCharacter;
+ }
+
+ const char *character() const {
+ return _character.c_str();
+ }
+
+ bool hasSlide() const {
+ return _hasSlide;
+ }
+
+ const char *slide() const {
+ return _slide.c_str();
+ }
+
+ const char *c_str() const {
+ return _buf;
+ }
+};
-LocationName::~LocationName() {
- free(_buf);
-}
/*
@@ -135,7 +169,6 @@ int Parallaction_ns::init() {
initResources();
initFonts();
- initCursors();
_locationParser = new LocationParser_ns(this);
_locationParser->init();
_programParser = new ProgramParser_ns(this);
@@ -156,6 +189,8 @@ int Parallaction_ns::init() {
_location._animations.push_front(_char._ani);
+ _saveLoad = new SaveLoad_ns(this, _saveFileMan);
+
Parallaction::init();
return 0;
@@ -181,32 +216,6 @@ void Parallaction_ns::freeFonts() {
}
-void Parallaction_ns::initCursors() {
- _comboArrow = _disk->loadPointer("pointer");
- _mouseArrow = _resMouseArrow;
-}
-
-void Parallaction_ns::setArrowCursor() {
-
- debugC(1, kDebugInput, "setting mouse cursor to arrow");
-
- // this stuff is needed to avoid artifacts with labels and selected items when switching cursors
- _input->stopHovering();
- _input->_activeItem._id = 0;
-
- _system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0);
-}
-
-void Parallaction_ns::setInventoryCursor(ItemName name) {
- assert(name > 0);
-
- byte *v8 = _comboArrow->getData(0);
-
- // FIXME: destination offseting is not clear
- _inventoryRenderer->drawItem(name, v8 + 7 * MOUSECOMBO_WIDTH + 7, MOUSECOMBO_WIDTH);
- _system->setMouseCursor(v8, MOUSECOMBO_WIDTH, MOUSECOMBO_HEIGHT, 0, 0, 0);
-}
-
void Parallaction_ns::callFunction(uint index, void* parm) {
assert(index < 25); // magic value 25 is maximum # of callables for Nippon Safes
@@ -216,13 +225,13 @@ void Parallaction_ns::callFunction(uint index, void* parm) {
int Parallaction_ns::go() {
- renameOldSavefiles();
+ _saveLoad->renameOldSavefiles();
- _globalTable = _disk->loadTable("global");
+ _globalFlagsNames = _disk->loadTable("global");
startGui();
- while ((_engineFlags & kEngineQuit) == 0) {
+ while (!quit()) {
runGame();
}
@@ -242,7 +251,7 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask)
v2 += 4;
}
- g_system->delayMillis(20);
+ _vm->_system->delayMillis(20);
_gfx->setPalette(pal);
_gfx->updateScreen();
}
@@ -253,10 +262,6 @@ void Parallaction_ns::switchBackground(const char* background, const char* mask)
}
-void Parallaction_ns::showSlide(const char *name) {
- _gfx->setBackground(kBackgroundSlide, name, 0, 0);
-}
-
void Parallaction_ns::runPendingZones() {
if (_activeZone) {
ZonePtr z = _activeZone; // speak Zone or sound
@@ -281,7 +286,7 @@ void Parallaction_ns::changeLocation(char *location) {
_zoneTrap = nullZonePtr;
- setArrowCursor();
+ _input->setArrowCursor();
_gfx->showGfxObj(_char._ani->gfxobj, false);
_location._animations.remove(_char._ani);
@@ -312,14 +317,10 @@ void Parallaction_ns::changeLocation(char *location) {
strcpy(_saveData1, locname.location());
parseLocation(_saveData1);
- _char._ani->_oldPos.x = -1000;
- _char._ani->_oldPos.y = -1000;
-
- _char._ani->field_50 = 0;
if (_location._startPosition.x != -1000) {
- _char._ani->_left = _location._startPosition.x;
- _char._ani->_top = _location._startPosition.y;
- _char._ani->_frame = _location._startFrame;
+ _char._ani->setX(_location._startPosition.x);
+ _char._ani->setY(_location._startPosition.y);
+ _char._ani->setF(_location._startFrame);
_location._startPosition.y = -1000;
_location._startPosition.x = -1000;
}
@@ -426,30 +427,35 @@ void Parallaction_ns::changeCharacter(const char *name) {
}
void Parallaction_ns::cleanupGame() {
+ _inTestResult = false;
_engineFlags &= ~kEngineTransformedDonna;
// this code saves main character animation from being removed from the following code
_location._animations.remove(_char._ani);
_numLocations = 0;
- _commandFlags = 0;
+ _globalFlags = 0;
memset(_localFlags, 0, sizeof(_localFlags));
memset(_locationNames, 0, sizeof(_locationNames));
// this flag tells freeZones to unconditionally remove *all* Zones
- _engineFlags |= kEngineQuit;
+ _vm->_quit = true;
freeZones();
freeAnimations();
// this dangerous flag can now be cleared
- _engineFlags &= ~kEngineQuit;
+ _vm->_quit = false;
// main character animation is restored
_location._animations.push_front(_char._ani);
_score = 0;
+ _soundMan->stopMusic();
+ _introSarcData3 = 200;
+ _introSarcData2 = 1;
+
return;
}
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index 6de0a7d7f5..a475f5701a 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -28,7 +28,10 @@
namespace Parallaction {
-char _tokens[20][MAX_TOKEN_LEN];
+#define MAX_TOKENS 50
+
+int _numTokens;
+char _tokens[MAX_TOKENS][MAX_TOKEN_LEN];
Script::Script(Common::ReadStream *input, bool disposeSource) : _input(input), _disposeSource(disposeSource), _line(0) {}
@@ -65,9 +68,11 @@ char *Script::readLine(char *buf, size_t bufSize) {
void Script::clearTokens() {
- for (uint16 i = 0; i < 20; i++)
+ for (uint16 i = 0; i < MAX_TOKENS; i++)
_tokens[i][0] = '\0';
+ _numTokens = 0;
+
return;
}
@@ -88,7 +93,7 @@ void Script::skip(const char* endToken) {
//
// The routine returns the unparsed portion of the input string 's'.
//
-char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes) {
+char *Script::parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes) {
enum STATES { NORMAL, QUOTED };
@@ -151,12 +156,14 @@ char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ign
uint16 Script::fillTokens(char* line) {
uint16 i = 0;
- while (strlen(line) > 0 && i < 20) {
+ while (strlen(line) > 0 && i < MAX_TOKENS) {
line = parseNextToken(line, _tokens[i], MAX_TOKEN_LEN, " \t\n");
line = Common::ltrim(line);
i++;
}
+ _numTokens = i;
+
return i;
}
@@ -176,13 +183,12 @@ uint16 Script::readLineToken(bool errorOnEOF) {
clearTokens();
- bool inBlockComment = false, inLineComment;
+ bool inBlockComment = false;
char buf[200];
char *line = NULL;
+ char *start;
do {
- inLineComment = false;
-
line = readLine(buf, 200);
if (line == NULL) {
@@ -191,21 +197,27 @@ uint16 Script::readLineToken(bool errorOnEOF) {
else
return 0;
}
- line = Common::ltrim(line);
+ start = Common::ltrim(line);
- if (isCommentLine(line)) {
- inLineComment = true;
+ if (isCommentLine(start)) {
+ // ignore this line
+ start[0] = '\0';
} else
- if (isStartOfCommentBlock(line)) {
+ if (isStartOfCommentBlock(start)) {
+ // mark this and the following lines as comment
inBlockComment = true;
} else
- if (isEndOfCommentBlock(line)) {
+ if (isEndOfCommentBlock(start)) {
+ // comment is finished, so stop ignoring
inBlockComment = false;
+ // the current line must be skipped, though,
+ // as it contains the end-of-comment marker
+ start[0] = '\0';
}
- } while (inLineComment || inBlockComment || strlen(line) == 0);
+ } while (inBlockComment || strlen(start) == 0);
- return fillTokens(line);
+ return fillTokens(start);
}
@@ -243,4 +255,187 @@ void Parser::parseStatement() {
}
+#define BLOCK_BASE 100
+
+class StatementDef {
+protected:
+ Common::String makeLineFromTokens() {
+ Common::String space(" ");
+ Common::String newLine("\n");
+ Common::String text;
+ for (int i = 0; i < _numTokens; i++)
+ text += (Common::String(_tokens[i]) + space);
+ text.deleteLastChar();
+ text += newLine;
+ return text;
+ }
+
+public:
+ uint _score;
+ const char* _name;
+
+
+ StatementDef(uint score, const char *name) : _score(score), _name(name) { }
+ virtual ~StatementDef() { }
+
+ virtual Common::String makeLine(Script &script) = 0;
+
+};
+
+
+class SimpleStatementDef : public StatementDef {
+
+public:
+ SimpleStatementDef(uint score, const char *name) : StatementDef(score, name) { }
+
+ Common::String makeLine(Script &script) {
+ return makeLineFromTokens();
+ }
+
+};
+
+
+
+class BlockStatementDef : public StatementDef {
+
+ const char* _ending1;
+ const char* _ending2;
+
+public:
+ BlockStatementDef(uint score, const char *name, const char *ending1, const char *ending2 = 0) : StatementDef(score, name), _ending1(ending1),
+ _ending2(ending2) { }
+
+ Common::String makeLine(Script &script) {
+ Common::String text = makeLineFromTokens();
+ bool end;
+ do {
+ script.readLineToken(true);
+ text += makeLineFromTokens();
+ end = !scumm_stricmp(_ending1, _tokens[0]) || (_ending2 && !scumm_stricmp(_ending2, _tokens[0]));
+ } while (!end);
+ return text;
+ }
+
+};
+
+class CommentStatementDef : public StatementDef {
+
+ Common::String parseComment(Script &script) {
+ Common::String result;
+ char buf[401];
+
+ do {
+ script.readLine(buf, 400);
+ buf[strlen(buf)-1] = '\0';
+ if (!scumm_stricmp(buf, "endtext"))
+ break;
+ result += Common::String(buf) + "\n";
+ } while (true);
+ result += "endtext\n";
+ return result;
+ }
+
+public:
+ CommentStatementDef(uint score, const char *name) : StatementDef(score, name) { }
+
+ Common::String makeLine(Script &script) {
+ Common::String text = makeLineFromTokens();
+ text += parseComment(script);
+ return text;
+ }
+
+};
+
+
+
+
+PreProcessor::PreProcessor() {
+ _defs.push_back(new SimpleStatementDef(1, "disk" ));
+ _defs.push_back(new SimpleStatementDef(2, "location" ));
+ _defs.push_back(new SimpleStatementDef(3, "localflags" ));
+ _defs.push_back(new SimpleStatementDef(4, "flags" ));
+ _defs.push_back(new SimpleStatementDef(5, "zeta" ));
+ _defs.push_back(new SimpleStatementDef(6, "music" ));
+ _defs.push_back(new SimpleStatementDef(7, "sound" ));
+ _defs.push_back(new SimpleStatementDef(8, "mask" ));
+ _defs.push_back(new SimpleStatementDef(9, "path" ));
+ _defs.push_back(new SimpleStatementDef(10, "character" ));
+ _defs.push_back(new CommentStatementDef(11, "comment" ));
+ _defs.push_back(new CommentStatementDef(12, "endcomment" ));
+ _defs.push_back(new BlockStatementDef(13, "ifchar", "endif" ));
+ _defs.push_back(new BlockStatementDef(BLOCK_BASE, "zone", "endanimation", "endzone" ));
+ _defs.push_back(new BlockStatementDef(BLOCK_BASE, "animation", "endanimation", "endzone" ));
+ _defs.push_back(new BlockStatementDef(1000, "commands", "endcommands" ));
+ _defs.push_back(new BlockStatementDef(1001, "acommands", "endcommands" ));
+ _defs.push_back(new BlockStatementDef(1002, "escape", "endcommands" ));
+ _defs.push_back(new SimpleStatementDef(2000, "endlocation"));
+}
+
+PreProcessor::~PreProcessor() {
+ DefList::iterator it = _defs.begin();
+ for (; it != _defs.end(); it++) {
+ delete *it;
+ }
+}
+
+StatementDef* PreProcessor::findDef(const char* name) {
+ DefList::iterator it = _defs.begin();
+ for (; it != _defs.end(); it++) {
+ if (!scumm_stricmp((*it)->_name, name)) {
+ return *it;
+ }
+ }
+ return 0;
+}
+
+
+
+uint PreProcessor::getDefScore(StatementDef* def) {
+ if (def->_score == BLOCK_BASE) {
+ _numZones++;
+ return (_numZones + BLOCK_BASE);
+ }
+ return def->_score;
+}
+
+
+void PreProcessor::preprocessScript(Script &script, StatementList &list) {
+ _numZones = 0;
+ Common::String text;
+ do {
+ script.readLineToken(false);
+ if (_numTokens == 0)
+ break;
+
+ StatementDef *def = findDef(_tokens[0]);
+ if (!def) {
+ error("PreProcessor::preprocessScript: unknown statement '%s' found\n", _tokens[0]);
+ }
+
+ text = def->makeLine(script);
+ int score = getDefScore(def);
+ list.push_back(StatementListNode(score, def->_name, text));
+ } while (true);
+ Common::sort(list.begin(), list.end());
+}
+
+
+
+
+void testPreprocessing(Parallaction *vm, const char *filename) {
+ Script *script = vm->_disk->loadLocation(filename);
+ StatementList list;
+ PreProcessor pp;
+ pp.preprocessScript(*script, list);
+ delete script;
+ Common::DumpFile dump;
+ dump.open(filename);
+ StatementList::iterator it = list.begin();
+ for ( ; it != list.end(); it++) {
+ dump.write((*it)._text.c_str(), (*it)._text.size());
+ }
+ dump.close();
+}
+
+
} // namespace Parallaction
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
index 488d437deb..f0cc448518 100644
--- a/engines/parallaction/parser.h
+++ b/engines/parallaction/parser.h
@@ -27,14 +27,14 @@
#define PARALLACTION_PARSER_H
#include "common/stream.h"
+#include "common/stack.h"
#include "parallaction/objects.h"
#include "parallaction/walk.h"
namespace Parallaction {
-char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes = false);
-
#define MAX_TOKEN_LEN 50
+extern int _numTokens;
extern char _tokens[][MAX_TOKEN_LEN];
class Script {
@@ -45,6 +45,7 @@ class Script {
void clearTokens();
uint16 fillTokens(char* line);
+ char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes = false);
public:
Script(Common::ReadStream *, bool _disposeSource = false);
@@ -63,6 +64,7 @@ typedef Common::Functor0<void> Opcode;
typedef Common::Array<const Opcode*> OpcodeSet;
+
class Parser {
public:
@@ -95,6 +97,7 @@ public:
class Parallaction_ns;
class Parallaction_br;
+
class LocationParser_ns {
protected:
@@ -128,9 +131,7 @@ protected:
// BRA specific
int numZones;
- char *bgName;
- char *maskName;
- char *pathName;
+ BackgroundInfo *info;
char *characterName;
} ctxt;
@@ -239,6 +240,23 @@ public:
};
+/*
+ TODO: adapt the parser to effectively use the
+ statement list provided by preprocessor as its
+ input, instead of relying on the current Script
+ class.
+
+ This would need a major rewrite of the parsing
+ system!
+
+ parseNextToken could then be sealed into the
+ PreProcessor class forever, together with the
+ _tokens[] and _numTokens stuff, now dangling as
+ global objects.
+
+ NS balloons code should be dealt with before,
+ though.
+*/
class LocationParser_br : public LocationParser_ns {
protected:
@@ -286,6 +304,7 @@ protected:
virtual void parseZoneTypeBlock(ZonePtr z);
void parsePathData(ZonePtr z);
+ void parseGetData(ZonePtr z);
public:
LocationParser_br(Parallaction_br *vm) : LocationParser_ns((Parallaction_ns*)vm), _vm(vm) {
@@ -401,6 +420,117 @@ public:
};
+
+/*
+ This simple stream is temporarily needed to hook the
+ preprocessor output to the parser. It will go away
+ when the parser is rewritten to fully exploit the
+ statement list provided by the preprocessor.
+*/
+
+class ReadStringStream : public Common::ReadStream {
+
+ char *_text;
+ uint32 _pos;
+ uint32 _size;
+
+public:
+ ReadStringStream(const Common::String &text) {
+ _text = new char[text.size() + 1];
+ strcpy(_text, text.c_str());
+ _size = text.size();
+ _pos = 0;
+ }
+
+ ~ReadStringStream() {
+ delete []_text;
+ }
+
+ uint32 read(void *buffer, uint32 size) {
+ if (_pos + size > _size) {
+ size = _size - _pos;
+ }
+ memcpy(buffer, _text + _pos, size);
+ _pos += size;
+ return size;
+ }
+
+ bool eos() const {
+ return _pos == _size; // FIXME (eos definition change)
+ }
+
+};
+
+
+/*
+ Demented as it may sound, the success of a parsing operation in the
+ original BRA depends on what has been parsed before. The game features
+ an innovative chaos system that involves the parser and the very game
+ engine, in order to inflict the user an unforgettable game experience.
+
+ Ok, now for the serious stuff.
+
+ The PreProcessor implemented here fixes the location scripts before
+ they are fed to the parser. It tries to do so by a preliminary scan
+ of the text file, during which a score is assigned to each statement
+ (more on this later). When the whole file has been analyzed, the
+ statements are sorted according to their score, to create a parsable
+ sequence.
+
+ For parsing, the statements in location scripts can be conveniently
+ divided into 3 groups:
+
+ * location definitions
+ * element definitions
+ * start-up commands
+
+ Since the parsing of element definitions requires location parameters
+ to be set, location definitions should be encountered first in the
+ script. Start-up commands in turn may reference elements, so they can
+ be parsed last. The first goal is to make sure the parser gets these
+ three sets in this order.
+
+ Location definitions must also be presented in a certain sequence,
+ because resource files are not fully self-describing. In short, some
+ critical game data in contained in certain files, that must obviously
+ be read before any other can be analyzed. This is the second goal.
+
+ TODO: some words about actual implementation.
+*/
+
+class StatementDef;
+
+struct StatementListNode {
+ int _score;
+ Common::String _name;
+ Common::String _text;
+
+ StatementListNode(int score, const Common::String &name, const Common::String &text) : _score(score), _name(name), _text(text) { }
+
+ bool operator<(const StatementListNode& node) const {
+ return _score < node._score;
+ }
+};
+typedef Common::List<StatementListNode> StatementList;
+
+
+class PreProcessor {
+ typedef Common::List<StatementDef*> DefList;
+
+ int _numZones;
+ DefList _defs;
+
+ StatementDef* findDef(const char* name);
+ uint getDefScore(StatementDef*);
+
+public:
+ PreProcessor();
+ ~PreProcessor();
+ void preprocessScript(Script &script, StatementList &list);
+};
+
+
+
} // namespace Parallaction
#endif
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index 3ba2beb288..4b11c5caa4 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -25,6 +25,7 @@
#include "parallaction/parallaction.h"
+
#include "parallaction/sound.h"
namespace Parallaction {
@@ -104,6 +105,7 @@ namespace Parallaction {
#define INST_ENDIF 30
#define INST_STOP 31
+
const char *_zoneTypeNamesRes_br[] = {
"examine",
"door",
@@ -314,7 +316,6 @@ DECLARE_LOCATION_PARSER(location) {
debugC(7, kDebugParser, "LOCATION_PARSER(location) ");
strcpy(_vm->_location._name, _tokens[1]);
- ctxt.bgName = strdup(_tokens[1]);
bool flip = false;
int nextToken;
@@ -329,15 +330,17 @@ DECLARE_LOCATION_PARSER(location) {
// TODO: handle background horizontal flip (via a context parameter)
if (_tokens[nextToken][0] != '\0') {
- _vm->_char._ani->_left = atoi(_tokens[nextToken]);
+ _vm->_char._ani->setX(atoi(_tokens[nextToken]));
nextToken++;
- _vm->_char._ani->_top = atoi(_tokens[nextToken]);
+ _vm->_char._ani->setY(atoi(_tokens[nextToken]));
nextToken++;
}
if (_tokens[nextToken][0] != '\0') {
- _vm->_char._ani->_frame = atoi(_tokens[nextToken]);
+ _vm->_char._ani->setF(atoi(_tokens[nextToken]));
}
+
+ _vm->_disk->loadScenery(*ctxt.info, _tokens[1], 0, 0);
}
@@ -463,17 +466,20 @@ DECLARE_LOCATION_PARSER(null) {
DECLARE_LOCATION_PARSER(mask) {
debugC(7, kDebugParser, "LOCATION_PARSER(mask) ");
- ctxt.maskName = strdup(_tokens[1]);
- _vm->_gfx->_backgroundInfo.layers[0] = atoi(_tokens[2]);
- _vm->_gfx->_backgroundInfo.layers[1] = atoi(_tokens[3]);
- _vm->_gfx->_backgroundInfo.layers[2] = atoi(_tokens[4]);
+ ctxt.info->layers[0] = 0;
+ ctxt.info->layers[1] = atoi(_tokens[2]);
+ ctxt.info->layers[2] = atoi(_tokens[3]);
+ ctxt.info->layers[3] = atoi(_tokens[4]);
+
+ _vm->_disk->loadScenery(*ctxt.info, 0, _tokens[1], 0);
+ ctxt.info->hasMask = true;
}
DECLARE_LOCATION_PARSER(path) {
debugC(7, kDebugParser, "LOCATION_PARSER(path) ");
- ctxt.pathName = strdup(_tokens[1]);
+ _vm->_disk->loadScenery(*ctxt.info, 0, 0, _tokens[1]);
}
@@ -491,7 +497,7 @@ DECLARE_LOCATION_PARSER(zeta) {
_vm->_location._zeta1 = atoi(_tokens[2]);
if (_tokens[3][0] != '\0') {
- _vm->_location._zeta2 = atoi(_tokens[1]);
+ _vm->_location._zeta2 = atoi(_tokens[3]);
} else {
_vm->_location._zeta2 = 50;
}
@@ -714,10 +720,7 @@ DECLARE_ZONE_PARSER(limits) {
ctxt.z->_linkedAnim = _vm->findAnimation(_tokens[1]);
ctxt.z->_linkedName = strdup(_tokens[1]);
} else {
- ctxt.z->_left = atoi(_tokens[1]);
- ctxt.z->_top = atoi(_tokens[2]);
- ctxt.z->_right = atoi(_tokens[3]);
- ctxt.z->_bottom = atoi(_tokens[4]);
+ ctxt.z->setBox(atoi(_tokens[1]), atoi(_tokens[2]), atoi(_tokens[3]), atoi(_tokens[4]));
}
}
@@ -768,6 +771,49 @@ void LocationParser_br::parsePathData(ZonePtr z) {
z->u.path = data;
}
+void LocationParser_br::parseGetData(ZonePtr z) {
+
+ GetData *data = new GetData;
+
+ do {
+
+ if (!scumm_stricmp(_tokens[0], "file")) {
+
+ GfxObj *obj = _vm->_gfx->loadGet(_tokens[1]);
+ obj->frame = 0;
+ obj->x = z->getX();
+ obj->y = z->getY();
+ data->gfxobj = obj;
+ }
+
+ if (!scumm_stricmp(_tokens[0], "mask")) {
+ if (ctxt.info->hasMask) {
+ Common::Rect rect;
+ data->gfxobj->getRect(0, rect);
+ data->_mask[0].create(rect.width(), rect.height());
+ _vm->_disk->loadMask(_tokens[1], data->_mask[0]);
+ data->_mask[1].create(rect.width(), rect.height());
+ data->_mask[1].bltCopy(0, 0, ctxt.info->mask, data->gfxobj->x, data->gfxobj->y, data->_mask->w, data->_mask->h);
+ data->hasMask = true;
+ } else {
+ warning("Mask for zone '%s' ignored, since background doesn't have one", z->_name);
+ }
+ }
+
+ if (!scumm_stricmp(_tokens[0], "path")) {
+
+ }
+
+ if (!scumm_stricmp(_tokens[0], "icon")) {
+ data->_icon = 4 + _vm->_objectsNames->lookup(_tokens[1]);
+ }
+
+ _script->readLineToken(true);
+ } while (scumm_stricmp(_tokens[0], "endzone"));
+
+ z->u.get = data;
+}
+
void LocationParser_br::parseZoneTypeBlock(ZonePtr z) {
debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type);
@@ -822,10 +868,10 @@ DECLARE_ANIM_PARSER(file) {
DECLARE_ANIM_PARSER(position) {
debugC(7, kDebugParser, "ANIM_PARSER(position) ");
- ctxt.a->_left = atoi(_tokens[1]);
- ctxt.a->_top = atoi(_tokens[2]);
- ctxt.a->_z = atoi(_tokens[3]);
- ctxt.a->_frame = atoi(_tokens[4]);
+ ctxt.a->setX(atoi(_tokens[1]));
+ ctxt.a->setY(atoi(_tokens[2]));
+ ctxt.a->setZ(atoi(_tokens[3]));
+ ctxt.a->setF(atoi(_tokens[4]));
}
@@ -841,15 +887,14 @@ DECLARE_ANIM_PARSER(moveto) {
DECLARE_ANIM_PARSER(endanimation) {
debugC(7, kDebugParser, "ANIM_PARSER(endanimation) ");
-
+#if 0
+ // I have disabled the following code since it seems useless.
+ // I will remove it after mask processing is done.
if (ctxt.a->gfxobj) {
ctxt.a->_right = ctxt.a->width();
ctxt.a->_bottom = ctxt.a->height();
}
-
- ctxt.a->_oldPos.x = -1000;
- ctxt.a->_oldPos.y = -1000;
-
+#endif
ctxt.a->_flags |= 0x1000000;
_parser->popTables();
@@ -992,16 +1037,16 @@ void ProgramParser_br::parseRValue(ScriptVar &v, const char *str) {
a = AnimationPtr(ctxt.a);
if (str[0] == 'X') {
- v.setField(&a->_left);
+ v.setField(a.get(), &Animation::getX);
} else
if (str[0] == 'Y') {
- v.setField(&a->_top);
+ v.setField(a.get(), &Animation::getY);
} else
if (str[0] == 'Z') {
- v.setField(&a->_z);
+ v.setField(a.get(), &Animation::getZ);
} else
if (str[0] == 'F') {
- v.setField(&a->_frame);
+ v.setField(a.get(), &Animation::getF);
} else
if (str[0] == 'N') {
v.setImmediate(a->getFrameNum());
@@ -1010,7 +1055,10 @@ void ProgramParser_br::parseRValue(ScriptVar &v, const char *str) {
v.setRandom(atoi(&str[1]));
} else
if (str[0] == 'L') {
+#if 0 // disabled because no references to lip sync has been found in the scripts
v.setField(&_vm->_lipSyncVal);
+#endif
+ warning("Lip sync instruction encountered! Please notify the team!");
}
}
@@ -1168,28 +1216,50 @@ void ProgramParser_br::init() {
INSTRUCTION_PARSER(endscript);
}
+
+/*
+ Ancillary routine to support hooking preprocessor and
+ parser.
+*/
+Common::ReadStream *getStream(StatementList &list) {
+ Common::String text;
+ StatementList::iterator it = list.begin();
+ for ( ; it != list.end(); it++) {
+ text += (*it)._text;
+ }
+ return new ReadStringStream(text);
+}
+
void LocationParser_br::parse(Script *script) {
+ PreProcessor pp;
+ StatementList list;
+ pp.preprocessScript(*script, list);
+ Script *script2 = new Script(getStream(list), true);
+
ctxt.numZones = 0;
- ctxt.bgName = 0;
- ctxt.maskName = 0;
- ctxt.pathName = 0;
ctxt.characterName = 0;
+ ctxt.info = new BackgroundInfo;
+
+ LocationParser_ns::parse(script2);
- LocationParser_ns::parse(script);
+ _vm->_gfx->setBackground(kBackgroundLocation, ctxt.info);
+ _vm->_pathBuffer = &ctxt.info->path;
- _vm->_gfx->setBackground(kBackgroundLocation, ctxt.bgName, ctxt.maskName, ctxt.pathName);
- _vm->_pathBuffer = &_vm->_gfx->_backgroundInfo.path;
+
+ ZoneList::iterator it = _vm->_location._zones.begin();
+ for ( ; it != _vm->_location._zones.end(); it++) {
+ bool visible = ((*it)->_flags & kFlagsRemove) == 0;
+ _vm->showZone((*it), visible);
+ }
if (ctxt.characterName) {
_vm->changeCharacter(ctxt.characterName);
}
- free(ctxt.bgName);
- free(ctxt.maskName);
- free(ctxt.pathName);
free(ctxt.characterName);
+ delete script2;
}
} // namespace Parallaction
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index ad0f714fdc..4b90e2364f 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -221,9 +221,6 @@ DECLARE_ANIM_PARSER(type) {
}
}
- ctxt.a->_oldPos.x = -1000;
- ctxt.a->_oldPos.y = -1000;
-
ctxt.a->_flags |= 0x1000000;
_parser->popTables();
@@ -267,9 +264,9 @@ DECLARE_ANIM_PARSER(file) {
DECLARE_ANIM_PARSER(position) {
debugC(7, kDebugParser, "ANIM_PARSER(position) ");
- ctxt.a->_left = atoi(_tokens[1]);
- ctxt.a->_top = atoi(_tokens[2]);
- ctxt.a->_z = atoi(_tokens[3]);
+ ctxt.a->setX(atoi(_tokens[1]));
+ ctxt.a->setY(atoi(_tokens[2]));
+ ctxt.a->setZ(atoi(_tokens[3]));
}
@@ -284,10 +281,6 @@ DECLARE_ANIM_PARSER(moveto) {
DECLARE_ANIM_PARSER(endanimation) {
debugC(7, kDebugParser, "ANIM_PARSER(endanimation) ");
-
- ctxt.a->_oldPos.x = -1000;
- ctxt.a->_oldPos.y = -1000;
-
ctxt.a->_flags |= 0x1000000;
_parser->popTables();
@@ -523,7 +516,7 @@ DECLARE_INSTRUCTION_PARSER(defLocal) {
}
ctxt.inst->_opA.setLocal(&ctxt.locals[index]);
- ctxt.inst->_opB.setImmediate(ctxt.locals[index]._value);
+ ctxt.inst->_opB.setImmediate(ctxt.locals[index].getValue());
ctxt.inst->_index = INST_SET;
}
@@ -558,16 +551,16 @@ void ProgramParser_ns::parseRValue(ScriptVar &v, const char *str) {
}
if (str[0] == 'X') {
- v.setField(&a->_left);
+ v.setField(a.get(), &Animation::getX);
} else
if (str[0] == 'Y') {
- v.setField(&a->_top);
+ v.setField(a.get(), &Animation::getY);
} else
if (str[0] == 'Z') {
- v.setField(&a->_z);
+ v.setField(a.get(), &Animation::getZ);
} else
if (str[0] == 'F') {
- v.setField(&a->_frame);
+ v.setField(a.get(), &Animation::getF);
}
}
@@ -588,16 +581,16 @@ void ProgramParser_ns::parseLValue(ScriptVar &v, const char *str) {
}
if (str[0] == 'X') {
- v.setField(&a->_left);
+ v.setField(a.get(), &Animation::getX, &Animation::setX);
} else
if (str[0] == 'Y') {
- v.setField(&a->_top);
+ v.setField(a.get(), &Animation::getY, &Animation::setY);
} else
if (str[0] == 'Z') {
- v.setField(&a->_z);
+ v.setField(a.get(), &Animation::getZ, &Animation::setZ);
} else
if (str[0] == 'F') {
- v.setField(&a->_frame);
+ v.setField(a.get(), &Animation::getF, &Animation::setF);
}
}
@@ -608,7 +601,7 @@ DECLARE_COMMAND_PARSER(flags) {
createCommand(_parser->_lookup);
- if (_vm->_globalTable->lookup(_tokens[1]) == Table::notFound) {
+ if (_vm->_globalFlagsNames->lookup(_tokens[1]) == Table::notFound) {
do {
char _al = _vm->_localFlagNames->lookup(_tokens[ctxt.nextToken]);
ctxt.nextToken++;
@@ -618,7 +611,7 @@ DECLARE_COMMAND_PARSER(flags) {
} else {
ctxt.cmd->u._flags |= kFlagsGlobal;
do {
- char _al = _vm->_globalTable->lookup(_tokens[1]);
+ char _al = _vm->_globalFlagsNames->lookup(_tokens[1]);
ctxt.nextToken++;
ctxt.cmd->u._flags |= 1 << (_al - 1);
} while (!scumm_stricmp(_tokens[ctxt.nextToken++], "|"));
@@ -759,11 +752,11 @@ void LocationParser_ns::parseCommandFlags() {
cmd->_flagsOn |= kFlagsEnter;
} else
if (!scumm_strnicmp(_tokens[_si], "no", 2)) {
- byte _al = _vm->_globalTable->lookup(&_tokens[_si][2]);
+ byte _al = _vm->_globalFlagsNames->lookup(&_tokens[_si][2]);
assert(_al != Table::notFound);
cmd->_flagsOff |= 1 << (_al - 1);
} else {
- byte _al = _vm->_globalTable->lookup(_tokens[_si]);
+ byte _al = _vm->_globalFlagsNames->lookup(_tokens[_si]);
assert(_al != Table::notFound);
cmd->_flagsOn |= 1 << (_al - 1);
}
@@ -880,7 +873,7 @@ Answer *LocationParser_ns::parseAnswer() {
if (!scumm_stricmp(_tokens[1], "global")) {
token = 2;
- flagNames = _vm->_globalTable;
+ flagNames = _vm->_globalFlagsNames;
answer->_yesFlags |= kFlagsGlobal;
} else {
token = 1;
@@ -992,12 +985,12 @@ DECLARE_LOCATION_PARSER(location) {
_vm->switchBackground(_vm->_location._name, mask);
if (_tokens[2][0] != '\0') {
- _vm->_char._ani->_left = atoi(_tokens[2]);
- _vm->_char._ani->_top = atoi(_tokens[3]);
+ _vm->_char._ani->setX(atoi(_tokens[2]));
+ _vm->_char._ani->setY(atoi(_tokens[3]));
}
if (_tokens[4][0] != '\0') {
- _vm->_char._ani->_frame = atoi(_tokens[4]);
+ _vm->_char._ani->setF(atoi(_tokens[4]));
}
}
@@ -1316,11 +1309,7 @@ DECLARE_ZONE_PARSER(endzone) {
DECLARE_ZONE_PARSER(limits) {
debugC(7, kDebugParser, "ZONE_PARSER(limits) ");
-
- ctxt.z->_left = atoi(_tokens[1]);
- ctxt.z->_top = atoi(_tokens[2]);
- ctxt.z->_right = atoi(_tokens[3]);
- ctxt.z->_bottom = atoi(_tokens[4]);
+ ctxt.z->setBox(atoi(_tokens[1]), atoi(_tokens[2]), atoi(_tokens[3]), atoi(_tokens[4]));
}
@@ -1411,8 +1400,8 @@ void LocationParser_ns::parseGetData(ZonePtr z) {
GfxObj *obj = _vm->_gfx->loadGet(_tokens[1]);
obj->frame = 0;
- obj->x = z->_left;
- obj->y = z->_top;
+ obj->x = z->getX();
+ obj->y = z->getY();
_vm->_gfx->showGfxObj(obj, visible);
data->gfxobj = obj;
@@ -1474,8 +1463,8 @@ void LocationParser_ns::parseDoorData(ZonePtr z) {
GfxObj *obj = _vm->_gfx->loadDoor(_tokens[1]);
obj->frame = frame;
- obj->x = z->_left;
- obj->y = z->_top;
+ obj->x = z->getX();
+ obj->y = z->getY();
_vm->_gfx->showGfxObj(obj, true);
data->gfxobj = obj;
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index 002295315d..d357e31cdc 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -31,6 +31,7 @@
#include "gui/message.h"
#include "parallaction/parallaction.h"
+#include "parallaction/saveload.h"
#include "parallaction/sound.h"
@@ -57,12 +58,11 @@ protected:
GUI::StaticTextWidget *_time;
GUI::StaticTextWidget *_playtime;
GUI::ContainerWidget *_container;
- Parallaction_ns *_vm;
uint8 _fillR, _fillG, _fillB;
public:
- SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine);
+ SaveLoadChooser(const String &title, const String &buttonLabel);
~SaveLoadChooser();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
@@ -73,34 +73,39 @@ public:
virtual void reflowLayout();
};
-Common::String Parallaction_ns::genSaveFileName(uint slot, bool oldStyle) {
+Common::String SaveLoad_ns::genOldSaveFileName(uint slot) {
assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT);
char s[20];
- sprintf(s, (oldStyle ? "game.%i" : "nippon.%.3d"), slot );
+ sprintf(s, "game.%i", slot);
return Common::String(s);
}
-Common::InSaveFile *Parallaction_ns::getInSaveFile(uint slot) {
+
+Common::String SaveLoad::genSaveFileName(uint slot) {
+ assert(slot < NUM_SAVESLOTS || slot == SPECIAL_SAVESLOT);
+
+ char s[20];
+ sprintf(s, "%s.%.3d", _saveFilePrefix.c_str(), slot);
+
+ return Common::String(s);
+}
+
+Common::InSaveFile *SaveLoad::getInSaveFile(uint slot) {
Common::String name = genSaveFileName(slot);
return _saveFileMan->openForLoading(name.c_str());
}
-Common::OutSaveFile *Parallaction_ns::getOutSaveFile(uint slot) {
+Common::OutSaveFile *SaveLoad::getOutSaveFile(uint slot) {
Common::String name = genSaveFileName(slot);
return _saveFileMan->openForSaving(name.c_str());
}
-void Parallaction_ns::doLoadGame(uint16 slot) {
-
- _soundMan->stopMusic();
+void SaveLoad_ns::doLoadGame(uint16 slot) {
- cleanupGame();
-
- _introSarcData3 = 200;
- _introSarcData2 = 1;
+ _vm->cleanupGame();
Common::InSaveFile *f = getInSaveFile(slot);
if (!f) return;
@@ -109,77 +114,77 @@ void Parallaction_ns::doLoadGame(uint16 slot) {
char n[16];
char l[16];
- f->readLine(s, 199);
+ f->readLine_OLD(s, 199);
- f->readLine(n, 15);
+ f->readLine_OLD(n, 15);
- f->readLine(l, 15);
+ f->readLine_OLD(l, 15);
- f->readLine(s, 15);
- _location._startPosition.x = atoi(s);
+ f->readLine_OLD(s, 15);
+ _vm->_location._startPosition.x = atoi(s);
- f->readLine(s, 15);
- _location._startPosition.y = atoi(s);
+ f->readLine_OLD(s, 15);
+ _vm->_location._startPosition.y = atoi(s);
- f->readLine(s, 15);
+ f->readLine_OLD(s, 15);
_score = atoi(s);
- f->readLine(s, 15);
- _commandFlags = atoi(s);
+ f->readLine_OLD(s, 15);
+ _globalFlags = atoi(s);
- f->readLine(s, 15);
+ f->readLine_OLD(s, 15);
// TODO (LIST): unify (and parametrize) calls to freeZones.
// We aren't calling freeAnimations because it is not needed, since
// kChangeLocation will trigger a complete deletion. Anyway, we still
- // need to invoke freeZones here with kEngineQuit set, because the
+ // need to invoke freeZones here with _quit set, because the
// call in changeLocation preserve certain zones.
- _engineFlags |= kEngineQuit;
- freeZones();
- _engineFlags &= ~kEngineQuit;
+ _vm->_quit = true;
+ _vm->freeZones();
+ _vm->_quit = false;
- _numLocations = atoi(s);
+ _vm->_numLocations = atoi(s);
uint16 _si;
- for (_si = 0; _si < _numLocations; _si++) {
- f->readLine(s, 20);
+ for (_si = 0; _si < _vm->_numLocations; _si++) {
+ f->readLine_OLD(s, 20);
s[strlen(s)] = '\0';
- strcpy(_locationNames[_si], s);
+ strcpy(_vm->_locationNames[_si], s);
- f->readLine(s, 15);
- _localFlags[_si] = atoi(s);
+ f->readLine_OLD(s, 15);
+ _vm->_localFlags[_si] = atoi(s);
}
- cleanInventory(false);
+ _vm->cleanInventory(false);
ItemName name;
uint32 value;
for (_si = 0; _si < 30; _si++) {
- f->readLine(s, 15);
+ f->readLine_OLD(s, 15);
value = atoi(s);
- f->readLine(s, 15);
+ f->readLine_OLD(s, 15);
name = atoi(s);
- addInventoryItem(name, value);
+ _vm->addInventoryItem(name, value);
}
delete f;
// force reload of character to solve inventory
// bugs, but it's a good maneuver anyway
- strcpy(_characterName1, "null");
+ strcpy(_vm->_characterName1, "null");
char tmp[PATH_LEN];
sprintf(tmp, "%s.%s" , l, n);
- scheduleLocationSwitch(tmp);
+ _vm->scheduleLocationSwitch(tmp);
return;
}
-void Parallaction_ns::doSaveGame(uint16 slot, const char* name) {
+void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) {
Common::OutSaveFile *f = getOutSaveFile(slot);
if (f == 0) {
@@ -202,30 +207,30 @@ void Parallaction_ns::doSaveGame(uint16 slot, const char* name) {
f->writeString(s);
f->writeString("\n");
- sprintf(s, "%s\n", _char.getFullName());
+ sprintf(s, "%s\n", _vm->_char.getFullName());
f->writeString(s);
sprintf(s, "%s\n", _saveData1);
f->writeString(s);
- sprintf(s, "%d\n", _char._ani->_left);
+ sprintf(s, "%d\n", _vm->_char._ani->getX());
f->writeString(s);
- sprintf(s, "%d\n", _char._ani->_top);
+ sprintf(s, "%d\n", _vm->_char._ani->getY());
f->writeString(s);
sprintf(s, "%d\n", _score);
f->writeString(s);
- sprintf(s, "%u\n", _commandFlags);
+ sprintf(s, "%u\n", _globalFlags);
f->writeString(s);
- sprintf(s, "%d\n", _numLocations);
+ sprintf(s, "%d\n", _vm->_numLocations);
f->writeString(s);
- for (uint16 _si = 0; _si < _numLocations; _si++) {
- sprintf(s, "%s\n%u\n", _locationNames[_si], _localFlags[_si]);
+ for (uint16 _si = 0; _si < _vm->_numLocations; _si++) {
+ sprintf(s, "%s\n%u\n", _vm->_locationNames[_si], _vm->_localFlags[_si]);
f->writeString(s);
}
const InventoryItem *item;
for (uint16 _si = 0; _si < 30; _si++) {
- item = getInventoryItem(_si);
+ item = _vm->getInventoryItem(_si);
sprintf(s, "%u\n%d\n", item->_id, item->_index);
f->writeString(s);
}
@@ -247,8 +252,8 @@ enum {
};
-SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction_ns *engine)
- : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0), _vm(engine) {
+SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
+ : Dialog("scummsaveload"), _list(0), _chooseButton(0), _gfxWidget(0) {
// _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
@@ -259,9 +264,6 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel,
_list->setEditable(true);
_list->setNumberingMode(GUI::kListNumberingOne);
- _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
- _container->setHints(GUI::THEME_HINT_USE_SHADOW);
-
_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
_date = new GUI::StaticTextWidget(this, 0, 0, 10, 10, "No date saved", GUI::kTextAlignCenter);
@@ -272,6 +274,9 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel,
new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", GUI::kCloseCmd, 0);
_chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
+
+ _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
+ _container->setHints(GUI::THEME_HINT_USE_SHADOW);
}
SaveLoadChooser::~SaveLoadChooser() {
@@ -335,7 +340,7 @@ void SaveLoadChooser::reflowLayout() {
Dialog::reflowLayout();
}
-int Parallaction_ns::buildSaveFileList(Common::StringList& l) {
+int SaveLoad_ns::buildSaveFileList(Common::StringList& l) {
char buf[200];
@@ -346,7 +351,7 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) {
Common::InSaveFile *f = getInSaveFile(i);
if (f) {
- f->readLine(buf, 199);
+ f->readLine_OLD(buf, 199);
delete f;
count++;
@@ -359,9 +364,9 @@ int Parallaction_ns::buildSaveFileList(Common::StringList& l) {
}
-int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) {
+int SaveLoad_ns::selectSaveFile(uint16 arg_0, const char* caption, const char* button) {
- SaveLoadChooser* slc = new SaveLoadChooser(caption, button, this);
+ SaveLoadChooser* slc = new SaveLoadChooser(caption, button);
Common::StringList l;
@@ -380,7 +385,7 @@ int Parallaction_ns::selectSaveFile(uint16 arg_0, const char* caption, const cha
-bool Parallaction_ns::loadGame() {
+bool SaveLoad_ns::loadGame() {
int _di = selectSaveFile( 0, "Load file", "Load" );
if (_di == -1) {
@@ -392,15 +397,15 @@ bool Parallaction_ns::loadGame() {
GUI::TimedMessageDialog dialog("Loading game...", 1500);
dialog.runModal();
- setArrowCursor();
+ _vm->_input->setArrowCursor();
return true;
}
-bool Parallaction_ns::saveGame() {
+bool SaveLoad_ns::saveGame() {
- if (!scumm_stricmp(_location._name, "caveau")) {
+ if (!scumm_stricmp(_vm->_location._name, "caveau")) {
return false;
}
@@ -418,7 +423,7 @@ bool Parallaction_ns::saveGame() {
}
-void Parallaction_ns::setPartComplete(const Character& character) {
+void SaveLoad_ns::setPartComplete(const char *part) {
char buf[30];
bool alreadyPresent = false;
@@ -426,10 +431,10 @@ void Parallaction_ns::setPartComplete(const Character& character) {
Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT);
if (inFile) {
- inFile->readLine(buf, 29);
+ inFile->readLine_OLD(buf, 29);
delete inFile;
- if (strstr(buf, character.getBaseName())) {
+ if (strstr(buf, part)) {
alreadyPresent = true;
}
}
@@ -437,7 +442,7 @@ void Parallaction_ns::setPartComplete(const Character& character) {
if (!alreadyPresent) {
Common::OutSaveFile *outFile = getOutSaveFile(SPECIAL_SAVESLOT);
outFile->writeString(buf);
- outFile->writeString(character.getBaseName());
+ outFile->writeString(part);
outFile->finalize();
delete outFile;
}
@@ -445,17 +450,20 @@ void Parallaction_ns::setPartComplete(const Character& character) {
return;
}
-bool Parallaction_ns::allPartsComplete() {
- char buf[30];
+void SaveLoad_ns::getGamePartProgress(bool *complete, int size) {
+ assert(complete && size >= 3);
+ char buf[30];
Common::InSaveFile *inFile = getInSaveFile(SPECIAL_SAVESLOT);
- inFile->readLine(buf, 29);
+ inFile->readLine_OLD(buf, 29);
delete inFile;
- return strstr(buf, "dino") && strstr(buf, "donna") && strstr(buf, "dough");
+ complete[0] = strstr(buf, "dino");
+ complete[1] = strstr(buf, "donna");
+ complete[2] = strstr(buf, "dough");
}
-void Parallaction_ns::renameOldSavefiles() {
+void SaveLoad_ns::renameOldSavefiles() {
bool exists[NUM_SAVESLOTS];
uint num = 0;
@@ -463,7 +471,7 @@ void Parallaction_ns::renameOldSavefiles() {
for (i = 0; i < NUM_SAVESLOTS; i++) {
exists[i] = false;
- Common::String name = genSaveFileName(i, true);
+ Common::String name = genOldSaveFileName(i);
Common::InSaveFile *f = _saveFileMan->openForLoading(name.c_str());
if (f) {
exists[i] = true;
@@ -491,8 +499,8 @@ void Parallaction_ns::renameOldSavefiles() {
uint success = 0;
for (i = 0; i < NUM_SAVESLOTS; i++) {
if (exists[i]) {
- Common::String oldName = genSaveFileName(i, true);
- Common::String newName = genSaveFileName(i, false);
+ Common::String oldName = genOldSaveFileName(i);
+ Common::String newName = genSaveFileName(i);
if (_saveFileMan->renameSavefile(oldName.c_str(), newName.c_str())) {
success++;
} else {
@@ -518,4 +526,28 @@ void Parallaction_ns::renameOldSavefiles() {
}
+bool SaveLoad_br::loadGame() {
+ // TODO: implement loadgame
+ return false;
+}
+
+bool SaveLoad_br::saveGame() {
+ // TODO: implement savegame
+ return false;
+}
+
+void SaveLoad_br::getGamePartProgress(bool *complete, int size) {
+ assert(complete && size >= 3);
+
+ // TODO: implement progress loading
+
+ complete[0] = true;
+ complete[1] = true;
+ complete[2] = true;
+}
+
+void SaveLoad_br::setPartComplete(const char *part) {
+ // TODO: implement progress saving
+}
+
} // namespace Parallaction
diff --git a/engines/parallaction/saveload.h b/engines/parallaction/saveload.h
new file mode 100644
index 0000000000..10bb8aafc2
--- /dev/null
+++ b/engines/parallaction/saveload.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+
+#ifndef PARALLACTION_SAVELOAD_H
+#define PARALLACTION_SAVELOAD_H
+
+namespace Parallaction {
+
+struct Character;
+
+
+class SaveLoad {
+
+protected:
+ Common::SaveFileManager *_saveFileMan;
+ Common::String _saveFilePrefix;
+
+ Common::String genSaveFileName(uint slot);
+ Common::InSaveFile *getInSaveFile(uint slot);
+ Common::OutSaveFile *getOutSaveFile(uint slot);
+
+public:
+ SaveLoad(Common::SaveFileManager* saveFileMan, const char *prefix) : _saveFileMan(saveFileMan), _saveFilePrefix(prefix) { }
+ virtual ~SaveLoad() { }
+
+ virtual bool loadGame() = 0;
+ virtual bool saveGame() = 0;
+ virtual void getGamePartProgress(bool *complete, int size) = 0;
+ virtual void setPartComplete(const char *part) = 0;
+
+ virtual void renameOldSavefiles() { }
+};
+
+class SaveLoad_ns : public SaveLoad {
+
+ Parallaction_ns *_vm;
+
+ Common::String _saveFileName;
+ Common::String genOldSaveFileName(uint slot);
+
+protected:
+ void renameOldSavefiles();
+ void doLoadGame(uint16 slot);
+ void doSaveGame(uint16 slot, const char* name);
+ int buildSaveFileList(Common::StringList& l);
+ int selectSaveFile(uint16 arg_0, const char* caption, const char* button);
+
+public:
+ SaveLoad_ns(Parallaction_ns *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "nippon"), _vm(vm) { }
+
+ virtual bool loadGame();
+ virtual bool saveGame();
+ virtual void getGamePartProgress(bool *complete, int size);
+ virtual void setPartComplete(const char *part);
+};
+
+class SaveLoad_br : public SaveLoad {
+
+ Parallaction_br *_vm;
+
+public:
+ SaveLoad_br(Parallaction_br *vm, Common::SaveFileManager *saveFileMan) : SaveLoad(saveFileMan, "bra"), _vm(vm) { }
+
+ virtual bool loadGame();
+ virtual bool saveGame();
+ virtual void getGamePartProgress(bool *complete, int size);
+ virtual void setPartComplete(const char *part);
+};
+
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp
index 2c5cf281dd..071495e8f1 100644
--- a/engines/parallaction/staticres.cpp
+++ b/engines/parallaction/staticres.cpp
@@ -29,7 +29,7 @@
namespace Parallaction {
-byte Parallaction_ns::_resMouseArrow[256] = {
+byte Input::_resMouseArrow_NS[256] = {
0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00,
0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00,
0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00,
@@ -335,12 +335,6 @@ const Parallaction_br::Callable Parallaction_br::_dosCallables[] = {
void Parallaction_ns::initResources() {
-// _zoneFlagNamesRes = _zoneFlagNamesRes_ns;
-// _zoneTypeNamesRes = _zoneTypeNamesRes_ns;
-// _commandsNamesRes = _commandsNamesRes_ns;
- _callableNamesRes = _callableNamesRes_ns;
-// _instructionNamesRes = _instructionNamesRes_ns;
-
_callableNames = new Table(ARRAYSIZE(_callableNamesRes_ns), _callableNamesRes_ns);
_localFlagNames = new FixedTable(NUM_LOCATIONS, 1);
@@ -356,13 +350,6 @@ void Parallaction_ns::initResources() {
void Parallaction_br::initResources() {
-// _zoneFlagNamesRes = _zoneFlagNamesRes_br;
-// _zoneTypeNamesRes = _zoneTypeNamesRes_br;
-// _commandsNamesRes = _commandsNamesRes_br;
- _callableNamesRes = _callableNamesRes_br;
-// _instructionNamesRes = _instructionNamesRes_br;
-// _audioCommandsNamesRes = _audioCommandsNamesRes_br;
-
_callableNames = new Table(ARRAYSIZE(_callableNamesRes_br), _callableNamesRes_br);
_localFlagNames = new FixedTable(NUM_LOCATIONS, 2);
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index bf8f423fd5..5fd67d26dc 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -479,7 +479,7 @@ void PathWalker_BR::finalizeWalk() {
_char.setFoot(foot);
#endif
- _ch->_ani->_frame = _dirFrame; // temporary solution
+ _ch->_ani->setF(_dirFrame); // temporary solution
#if 0
// TODO: support scrolling ;)
@@ -515,7 +515,7 @@ void PathWalker_BR::walk() {
GfxObj *obj = _ch->_ani->gfxobj;
Common::Rect rect;
- obj->getRect(_ch->_ani->_frame, rect);
+ obj->getRect(_ch->_ani->getF(), rect);
uint scale;
if (rect.bottom > _vm->_location._zeta0) {
@@ -609,11 +609,11 @@ void PathWalker_BR::walk() {
if (_fieldC) {
debugC(9, kDebugWalk, "PathWalker_BR::walk, foot moved from (%i, %i) to (%i, %i)\n", _startFoot.x, _startFoot.y, newpos.x, newpos.y);
- _ch->_ani->_frame = walkFrame + _dirFrame + 1;
+ _ch->_ani->setF(walkFrame + _dirFrame + 1);
_startFoot.x = newpos.x;
_startFoot.y = newpos.y;
_ch->setFoot(_startFoot);
- _ch->_ani->_z = newpos.y;
+ _ch->_ani->setZ(newpos.y);
}
if (_fieldC || !_ch->_walkPath.empty()) {
diff --git a/engines/queen/input.cpp b/engines/queen/input.cpp
index 9f03c341c9..84e21fbcaa 100644
--- a/engines/queen/input.cpp
+++ b/engines/queen/input.cpp
@@ -118,9 +118,10 @@ void Input::delay(uint amount) {
case Common::EVENT_RBUTTONDOWN:
_mouseButton |= MOUSE_RBUTTON;
break;
-
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->quitGame();
+ if (_cutawayRunning)
+ _cutawayQuit = true;
return;
default:
diff --git a/engines/queen/journal.cpp b/engines/queen/journal.cpp
index 0327fb74b8..7846fa5c36 100644
--- a/engines/queen/journal.cpp
+++ b/engines/queen/journal.cpp
@@ -84,8 +84,8 @@ void Journal::use() {
case Common::EVENT_WHEELDOWN:
handleMouseWheel(1);
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->quitGame();
return;
default:
break;
@@ -385,16 +385,18 @@ void Journal::drawPanelText(int y, const char *text) {
char s[128];
strncpy(s, text, 127);
s[127] = 0;
+ char *p;
+
// remove leading and trailing spaces (necessary for spanish version)
- for (char *p = s + strlen(s) - 1; p >= s && *p == ' '; --p) {
+ for (p = s + strlen(s) - 1; p >= s && *p == ' '; --p) {
*p = 0;
}
text = s;
- for (char *p = s; *p == ' '; ++p) {
+ for (p = s; *p == ' '; ++p) {
text = p + 1;
}
// draw the substrings
- char *p = (char *)strchr(text, ' ');
+ p = (char *)strchr(text, ' ');
if (!p) {
int x = (128 - _vm->display()->textWidth(text)) / 2;
_vm->display()->setText(x, y, text, false);
diff --git a/engines/queen/logic.cpp b/engines/queen/logic.cpp
index 9e4770553c..7fcc761018 100644
--- a/engines/queen/logic.cpp
+++ b/engines/queen/logic.cpp
@@ -2076,6 +2076,8 @@ bool LogicDemo::changeToSpecialRoom() {
displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
playCutaway("CLOGO.CUT");
sceneReset();
+ if (_vm->quit())
+ return true;
currentRoom(ROOM_HOTEL_LOBBY);
entryObj(584);
displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true);
@@ -2129,7 +2131,11 @@ bool LogicGame::changeToSpecialRoom() {
} else if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) {
displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
playCutaway("COPY.CUT");
+ if (_vm->quit())
+ return true;
playCutaway("CLOGO.CUT");
+ if (_vm->quit())
+ return true;
if (_vm->resource()->getPlatform() != Common::kPlatformAmiga) {
if (ConfMan.getBool("alt_intro") && _vm->resource()->isCD()) {
playCutaway("CINTR.CUT");
@@ -2137,7 +2143,11 @@ bool LogicGame::changeToSpecialRoom() {
playCutaway("CDINT.CUT");
}
}
+ if (_vm->quit())
+ return true;
playCutaway("CRED.CUT");
+ if (_vm->quit())
+ return true;
_vm->display()->palSetPanel();
sceneReset();
currentRoom(ROOM_HOTEL_LOBBY);
diff --git a/engines/queen/midiadlib.cpp b/engines/queen/midiadlib.cpp
index 155bb66716..200c7282f9 100644
--- a/engines/queen/midiadlib.cpp
+++ b/engines/queen/midiadlib.cpp
@@ -132,7 +132,7 @@ int AdlibMidiDriver::open() {
adlibSetNoteVolume(i, 0);
adlibTurnNoteOff(i);
}
- _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
return 0;
}
diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp
index c95e44b477..6cdd020b8f 100644
--- a/engines/queen/queen.cpp
+++ b/engines/queen/queen.cpp
@@ -60,9 +60,12 @@ public:
virtual const char *getName() const;
virtual const char *getCopyright() const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const FSList &fslist) const;
+ virtual GameList detectGames(const Common::FSList &fslist) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
virtual PluginError createInstance(OSystem *syst, Engine **engine) const;
};
@@ -75,6 +78,14 @@ const char *QueenMetaEngine::getCopyright() const {
return "Flight of the Amazon Queen (C) John Passfield and Steve Stamatiadis";
}
+bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
GameList QueenMetaEngine::getSupportedGames() const {
GameList games;
games.push_back(queenGameDescriptor);
@@ -88,11 +99,11 @@ GameDescriptor QueenMetaEngine::findGame(const char *gameid) const {
return GameDescriptor();
}
-GameList QueenMetaEngine::detectGames(const FSList &fslist) const {
+GameList QueenMetaEngine::detectGames(const Common::FSList &fslist) const {
GameList detectedGames;
// Iterate over all files in the given directory
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory()) {
continue;
}
@@ -121,6 +132,46 @@ GameList QueenMetaEngine::detectGames(const FSList &fslist) const {
return detectedGames;
}
+SaveStateList QueenMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[32];
+ Common::String pattern = target;
+ pattern += ".s??";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 2 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ for (int i = 0; i < 4; i++)
+ in->readUint32BE();
+ in->read(saveDesc, 32);
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void QueenMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".s%02d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
PluginError QueenMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
assert(engine);
*engine = new Queen::QueenEngine(syst);
@@ -180,6 +231,10 @@ void QueenEngine::checkOptionSettings() {
}
}
+void QueenEngine::syncSoundSettings() {
+ readOptionSettings();
+}
+
void QueenEngine::readOptionSettings() {
_sound->setVolume(ConfMan.getInt("music_volume"));
_sound->musicToggle(!ConfMan.getBool("music_mute"));
@@ -381,8 +436,8 @@ int QueenEngine::go() {
loadGameState(ConfMan.getInt("save_slot"));
}
_lastSaveTime = _lastUpdateTime = _system->getMillis();
- _quit = false;
- while (!_quit) {
+
+ while (!quit()) {
if (_logic->newRoom() > 0) {
_logic->update();
_logic->oldRoom(_logic->currentRoom());
@@ -428,10 +483,6 @@ int QueenEngine::init() {
_logic = new LogicGame(this);
}
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
- // Set mixer music volume to maximum, since music volume is regulated by MusicPlayer's MIDI messages
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
-
_sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression());
_walk = new Walk(this);
//_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0;
diff --git a/engines/queen/queen.h b/engines/queen/queen.h
index 0beb557b36..66931e037d 100644
--- a/engines/queen/queen.h
+++ b/engines/queen/queen.h
@@ -29,7 +29,7 @@
#include "engines/engine.h"
namespace Common {
- class InSaveFile;
+ class SeekableReadStream;
}
#if defined(_WIN32_WCE) && (_WIN32_WCE <= 300)
@@ -97,13 +97,13 @@ public:
void checkOptionSettings();
void readOptionSettings();
void writeOptionSettings();
+ virtual void syncSoundSettings();
int talkSpeed() const { return _talkSpeed; }
void talkSpeed(int speed) { _talkSpeed = speed; }
bool subtitles() const { return _subtitles; }
void subtitles(bool enable) { _subtitles = enable; }
- void quitGame() { _quit = true; }
-
+
void update(bool checkPlayerInput = false);
bool canLoadOrSave() const;
@@ -112,7 +112,7 @@ public:
void makeGameStateName(int slot, char *buf) const;
int getGameStateSlot(const char *filename) const;
void findGameStateDescriptions(char descriptions[100][32]);
- Common::InSaveFile *readGameStateHeader(int slot, GameStateHeader *gsh);
+ Common::SeekableReadStream *readGameStateHeader(int slot, GameStateHeader *gsh);
enum {
SAVESTATE_CUR_VER = 1,
@@ -137,7 +137,6 @@ protected:
int _talkSpeed;
bool _subtitles;
- bool _quit;
uint32 _lastSaveTime;
uint32 _lastUpdateTime;
diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp
index b3bd663baf..38d841e96a 100644
--- a/engines/queen/resource.cpp
+++ b/engines/queen/resource.cpp
@@ -132,7 +132,7 @@ void Resource::loadTextFile(const char *filename, Common::StringList &stringList
seekResourceFile(re->bundle, re->offset);
char buf[512];
Common::SeekableSubReadStream stream(&_resourceFile, re->offset, re->offset + re->size);
- while (stream.readLine(buf, 512)) {
+ while (stream.readLine_OLD(buf, 512)) {
stringList.push_back(buf);
}
}
diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp
index f4e0116cf1..ccaac8227d 100644
--- a/engines/queen/sound.cpp
+++ b/engines/queen/sound.cpp
@@ -35,6 +35,7 @@
#include "queen/queen.h"
#include "queen/resource.h"
+#include "sound/audiostream.h"
#include "sound/flac.h"
#include "sound/mididrv.h"
#include "sound/mp3.h"
@@ -45,6 +46,59 @@
namespace Queen {
+// The sounds in the PC versions are all played at 11840 Hz. Unfortunately, we
+// did not know that at the time, so there are plenty of compressed versions
+// which claim that they should be played at 11025 Hz. This "wrapper" class
+// works around that.
+
+class AudioStreamWrapper : public Audio::AudioStream {
+protected:
+ Audio::AudioStream *_stream;
+ int _rate;
+
+public:
+ AudioStreamWrapper(Audio::AudioStream *stream) {
+ _stream = stream;
+
+ int rate = _stream->getRate();
+
+ // A file where the sample rate claims to be 11025 Hz is
+ // probably compressed with the old tool. We force the real
+ // sample rate, which is 11840 Hz.
+ //
+ // However, a file compressed with the newer tool is not
+ // guaranteed to have a sample rate of 11840 Hz. LAME will
+ // automatically resample it to 12000 Hz. So in all other
+ // cases, we use the rate from the file.
+
+ if (rate == 11025)
+ _rate = 11840;
+ else
+ _rate = rate;
+ }
+ ~AudioStreamWrapper() {
+ delete _stream;
+ }
+ int readBuffer(int16 *buffer, const int numSamples) {
+ return _stream->readBuffer(buffer, numSamples);
+ }
+ bool isStereo() const {
+ return _stream->isStereo();
+ }
+ bool endOfData() const {
+ return _stream->endOfData();
+ }
+ bool endOfStream() {
+ return _stream->endOfStream();
+ }
+ int getRate() const {
+ return _rate;
+ }
+ int32 getTotalPlayTime() {
+ return _stream->getTotalPlayTime();
+ }
+};
+
class SilentSound : public PCSound {
public:
SilentSound(Audio::Mixer *mixer, QueenEngine *vm) : PCSound(mixer, vm) {}
@@ -69,7 +123,7 @@ protected:
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) {
Common::MemoryReadStream *tmp = f->readStream(size);
assert(tmp);
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeMP3Stream(tmp, true));
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeMP3Stream(tmp, true)));
}
};
#endif
@@ -82,7 +136,7 @@ protected:
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) {
Common::MemoryReadStream *tmp = f->readStream(size);
assert(tmp);
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeVorbisStream(tmp, true));
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeVorbisStream(tmp, true)));
}
};
#endif
@@ -95,7 +149,7 @@ protected:
void playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *soundHandle) {
Common::MemoryReadStream *tmp = f->readStream(size);
assert(tmp);
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, Audio::makeFlacStream(tmp, true));
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, soundHandle, new AudioStreamWrapper(Audio::makeFlacStream(tmp, true)));
}
};
#endif // #ifdef USE_FLAC
@@ -224,8 +278,6 @@ void PCSound::playSpeech(const char *base) {
void PCSound::setVolume(int vol) {
Sound::setVolume(vol);
- // Set mixer music volume to maximum, since music volume is regulated by MusicPlayer's MIDI messages
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
_music->setVolume(vol);
}
@@ -279,7 +331,8 @@ void SBSound::playSoundData(Common::File *f, uint32 size, Audio::SoundHandle *so
if (sound) {
f->read(sound, size);
byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE;
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, soundHandle, sound, size, 11840, flags);
+ Audio::Mixer::SoundType type = (soundHandle == &_speechHandle) ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType;
+ _mixer->playRaw(type, soundHandle, sound, size, 11840, flags);
}
}
diff --git a/engines/queen/talk.cpp b/engines/queen/talk.cpp
index ff18ef37d1..fa2ca669cd 100644
--- a/engines/queen/talk.cpp
+++ b/engines/queen/talk.cpp
@@ -807,7 +807,7 @@ void Talk::speakSegment(
switch (command) {
case SPEAK_PAUSE:
- for (i = 0; i < 10 && !_vm->input()->talkQuit(); i++) {
+ for (i = 0; i < 10 && !_vm->input()->talkQuit() && !_vm->quit(); i++) {
_vm->update();
}
return;
diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp
index 9fffb0f8bf..493c05022c 100644
--- a/engines/saga/animation.cpp
+++ b/engines/saga/animation.cpp
@@ -579,6 +579,9 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
_vm->_events->queue(&event);
}
return;
+ } else {
+ anim->currentFrame = 0;
+ anim->completed = 0;
}
}
@@ -866,7 +869,7 @@ int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) {
readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE
- while (!readS.eos()) {
+ while (readS.pos() != readS.size()) {
if (reallyFill) {
anim->frameOffsets[currentFrame] = readS.pos();
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index 9c897d8ebc..a31e9b755a 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -147,9 +147,20 @@ public:
return "Inherit the Earth (C) Wyrmkeep Entertainment";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
};
+bool SagaMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Saga::SAGAGameDescription *gd = (const Saga::SAGAGameDescription *)desc;
if (gd) {
@@ -158,6 +169,46 @@ bool SagaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
return gd != 0;
}
+SaveStateList SagaMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[SAVE_TITLE_SIZE];
+ Common::String pattern = target;
+ pattern += ".s??";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 2 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ for (int i = 0; i < 3; i++)
+ in->readUint32BE();
+ in->read(saveDesc, SAVE_TITLE_SIZE);
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void SagaMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".s%02d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
#if PLUGIN_ENABLED_DYNAMIC(SAGA)
REGISTER_PLUGIN_DYNAMIC(SAGA, PLUGIN_TYPE_ENGINE, SagaMetaEngine);
#else
diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h
index 7fee5fbee1..c85b5b830f 100644
--- a/engines/saga/displayinfo.h
+++ b/engines/saga/displayinfo.h
@@ -64,7 +64,7 @@ struct GameDisplayInfo {
int saveReminderWidth;
int saveReminderHeight;
int saveReminderFirstSpriteNumber;
- int saveReminderSecondSpriteNumber;
+ int saveReminderNumSprites;
int leftPortraitXOffset;
int leftPortraitYOffset;
@@ -230,7 +230,8 @@ static const GameDisplayInfo ITE_DisplayInfo = {
15, // status BG color
308,137, // save reminder pos
12,12, // save reminder w & h
- 6,7, // save reminder sprite numbers
+ 6, // save reminder first sprite number
+ 2, // number of save reminder sprites
5, 4, // left portrait x, y offset
274, 4, // right portrait x, y offset
@@ -348,9 +349,9 @@ static PanelButton IHNM_QuitPanelButtons[] = {
};
static PanelButton IHNM_LoadPanelButtons[] = {
- // TODO
- {kPanelButtonLoad, 101,19, 60,16, kTextOK,'o',0, 0,0,0},
- {kPanelButtonLoadText, -1,5, 0,0, kTextLoadSuccessful,'-',0, 0,0,0},
+ {kPanelButtonLoad, 26,80, 80,25, kTextOK,'o',0, 0,0,0},
+ {kPanelButtonLoad, 156,80, 80,25, kTextCancel,'c',0, 0,0,0},
+ {kPanelButtonLoadText, -1,30, 0,0, kTextLoadSavedGame,'-',0, 0,0,0},
};
static PanelButton IHNM_SavePanelButtons[] = {
@@ -376,7 +377,8 @@ static const GameDisplayInfo IHNM_DisplayInfo = {
250, // status BG color
616, 304, // save reminder pos
24, 24, // save reminder w&h
- 0,1, // save reminder sprite numbers
+ 0, // save reminder first sprite number
+ 16, // number of save reminder sprites
11, 12, // left portrait x, y offset
-1, -1, // right portrait x, y offset
diff --git a/engines/saga/input.cpp b/engines/saga/input.cpp
index ac80d87dd0..61b729b701 100644
--- a/engines/saga/input.cpp
+++ b/engines/saga/input.cpp
@@ -141,9 +141,6 @@ int SagaEngine::processInput() {
break;
case Common::EVENT_MOUSEMOVE:
break;
- case Common::EVENT_QUIT:
- shutDown();
- break;
default:
break;
}
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index 1d048baaad..38d126c5d4 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -94,7 +94,7 @@ static int IHNMTextStringIdsLUT[56] = {
8, // Give
10, // Options
11, // Test
- 12, //
+ 12, // Demo
13, // Help
14, // Quit Game
16, // Fast
@@ -358,15 +358,12 @@ void Interface::saveReminderCallback(void *refCon) {
}
void Interface::updateSaveReminder() {
- // TODO: finish this
- /*
if (_active && _panelMode == kPanelMain) {
- _vm->_timer->removeTimerProc(&saveReminderCallback);
- _saveReminderState = (_saveReminderState == 0) ? 1 : 0;
+ _saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1;
drawStatusBar();
- _vm->_timer->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
+ _vm->_timer->removeTimerProc(&saveReminderCallback);
+ _vm->_timer->installTimerProc(&saveReminderCallback, ((_vm->getGameType() == GType_ITE) ? TIMETOBLINK_ITE : TIMETOBLINK_IHNM), this);
}
- */
}
int Interface::activate() {
@@ -423,7 +420,7 @@ void Interface::setMode(int mode) {
if (mode == kPanelMain) {
_inMainMode = true;
- _saveReminderState = 1; //TODO: blinking timeout
+ _saveReminderState = 1;
} else if (mode == kPanelChapterSelection) {
_saveReminderState = 1;
} else if (mode == kPanelNull) {
@@ -688,7 +685,7 @@ bool Interface::processAscii(Common::KeyState keystate) {
setMode(kPanelMain);
_vm->_script->setNoPendingVerb();
} else if (ascii == 'q' || ascii == 'Q') {
- _vm->shutDown();
+ _vm->quitGame();
}
break;
case kPanelBoss:
@@ -905,10 +902,13 @@ void Interface::drawPanelText(Surface *ds, InterfacePanel *panel, PanelButton *p
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
} else {
- if (panelButton->id < 39 || panelButton->id > 50) {
+ if ((panelButton->id < 39 || panelButton->id > 50) && panelButton->id != kTextLoadSavedGame) {
// Read non-hardcoded strings from the LUT string table, loaded from the game
// data files
text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[panelButton->id]);
+ } else if (panelButton->id == kTextLoadSavedGame) {
+ // a bit of a kludge, but it will do
+ text = _vm->getTextString(52);
} else {
// Hardcoded strings in IHNM are read from the ITE hardcoded strings
text = _vm->getTextString(panelButton->id);
@@ -1081,7 +1081,7 @@ void Interface::setQuit(PanelButton *panelButton) {
if (_vm->getGameId() == GID_IHNM_DEMO)
_vm->_scene->creditsScene(); // display sales info for IHNM demo
else
- _vm->shutDown();
+ _vm->quitGame();
break;
}
}
@@ -1142,7 +1142,22 @@ void Interface::setLoad(PanelButton *panelButton) {
_loadPanel.currentButton = NULL;
switch (panelButton->id) {
case kTextOK:
- setMode(kPanelMain);
+ if (_vm->getGameType() == GType_ITE) {
+ setMode(kPanelMain);
+ } else {
+ if (_vm->getSaveFilesCount() > 0) {
+ if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
+ debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ setMode(kPanelMain);
+ _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
+ _vm->syncSoundSettings();
+ }
+ }
+ }
+ break;
+ case kTextCancel:
+ // IHNM only
+ setMode(kPanelOption);
break;
}
}
@@ -1402,6 +1417,10 @@ void Interface::setSave(PanelButton *panelButton) {
fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
_vm->save(fileName, _textInputString);
}
+ _vm->_timer->removeTimerProc(&saveReminderCallback);
+ _vm->_timer->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
+ setSaveReminderState(1);
+
_textInput = false;
setMode(kPanelOption);
break;
@@ -1573,7 +1592,6 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) {
}
void Interface::setOption(PanelButton *panelButton) {
- char * fileName;
_optionPanel.currentButton = NULL;
switch (panelButton->id) {
case kTextContinuePlaying:
@@ -1594,13 +1612,17 @@ void Interface::setOption(PanelButton *panelButton) {
setMode(kPanelQuit);
break;
case kTextLoad:
- if (_vm->getSaveFilesCount() > 0) {
- if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
- debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
- fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
- setMode(kPanelMain);
- _vm->load(fileName);
+ if (_vm->getGameType() == GType_ITE) {
+ if (_vm->getSaveFilesCount() > 0) {
+ if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
+ debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ setMode(kPanelMain);
+ _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
+ _vm->syncSoundSettings();
+ }
}
+ } else {
+ setMode(kPanelLoad);
}
break;
case kTextSave:
@@ -1625,14 +1647,16 @@ void Interface::setOption(PanelButton *panelButton) {
}
break;
case kTextMusic:
- _vm->_musicVolume = (_vm->_musicVolume + 1) % 11;
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
- ConfMan.setInt("music_volume", _vm->_musicVolume * 25);
+ _vm->_musicVolume = _vm->_musicVolume + 25;
+ if (_vm->_musicVolume > 255) _vm->_musicVolume = 0;
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
+ ConfMan.setInt("music_volume", _vm->_musicVolume);
break;
case kTextSound:
- _vm->_soundVolume = (_vm->_soundVolume + 1) % 11;
- _vm->_sound->setVolume(_vm->_soundVolume == 10 ? 255 : _vm->_soundVolume * 25);
- ConfMan.setInt("sfx_volume", _vm->_soundVolume * 25);
+ _vm->_soundVolume = _vm->_soundVolume + 25;
+ if (_vm->_soundVolume > 255) _vm->_soundVolume = 0;
+ ConfMan.setInt("sound_volume", _vm->_soundVolume);
+ _vm->_sound->setVolume();
break;
case kTextVoices:
if (_vm->_voiceFilesExist) {
@@ -1650,6 +1674,11 @@ void Interface::setOption(PanelButton *panelButton) {
_vm->_subtitlesEnabled = true; // Set it to "Text"
_vm->_voicesEnabled = false;
}
+
+ _vm->_speechVolume = _vm->_speechVolume + 25;
+ if (_vm->_speechVolume > 255) _vm->_speechVolume = 0;
+ ConfMan.setInt("speech_volume", _vm->_speechVolume);
+ _vm->_sound->setVolume();
ConfMan.setBool("subtitles", _vm->_subtitlesEnabled);
ConfMan.setBool("voices", _vm->_voicesEnabled);
@@ -1897,7 +1926,7 @@ void Interface::drawStatusBar() {
rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
_vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_saveReminderSprites,
- _saveReminderState == 1 ? _vm->getDisplayInfo().saveReminderFirstSpriteNumber : _vm->getDisplayInfo().saveReminderSecondSpriteNumber,
+ _vm->getDisplayInfo().saveReminderFirstSpriteNumber + _saveReminderState - 1,
rect, 256);
}
@@ -2250,13 +2279,13 @@ void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelBut
break;
case kTextMusic:
if (_vm->_musicVolume)
- textId = kText10Percent + _vm->_musicVolume - 1;
+ textId = kText10Percent + _vm->_musicVolume / 25 - 1;
else
textId = kTextOff;
break;
case kTextSound:
if (_vm->_soundVolume)
- textId = kText10Percent + _vm->_soundVolume - 1;
+ textId = kText10Percent + _vm->_soundVolume / 25 - 1;
else
textId = kTextOff;
break;
diff --git a/engines/saga/interface.h b/engines/saga/interface.h
index 2091c9f071..46df12ed51 100644
--- a/engines/saga/interface.h
+++ b/engines/saga/interface.h
@@ -59,8 +59,9 @@ enum InterfaceUpdateFlags {
#define RID_IHNM_BOSS_SCREEN 19 // not in demo
#define RID_ITE_TYCHO_MAP 1686
#define RID_ITE_SPR_CROSSHAIR (73 + 9)
-#define TIMETOSAVE (kScriptTimeTicksPerSecond * 1000 * 60 * 30)
-#define TIMETOBLINK (kScriptTimeTicksPerSecond * 1000 * 1)
+#define TIMETOSAVE (1000000 * 60 * 30) // 30 minutes
+#define TIMETOBLINK_ITE (1000000 * 1)
+#define TIMETOBLINK_IHNM (1000000 / 10)
// Converse-specific stuff
diff --git a/engines/saga/introproc_ihnm.cpp b/engines/saga/introproc_ihnm.cpp
index 6614f4098f..aaa428ca53 100644
--- a/engines/saga/introproc_ihnm.cpp
+++ b/engines/saga/introproc_ihnm.cpp
@@ -59,8 +59,12 @@ int Scene::IHNMStartProc() {
// Play Cyberdreams logo for 168 frames
if (!playTitle(0, logoLength, true)) {
+ if (_vm->quit())
+ return !SUCCESS;
// Play Dreamers Guild logo for 10 seconds
if (!playLoopingTitle(1, 10)) {
+ if (_vm->quit())
+ return !SUCCESS;
// Play the title music
_vm->_music->play(1, MUSIC_NORMAL);
// Play title screen
@@ -70,6 +74,8 @@ int Scene::IHNMStartProc() {
} else {
_vm->_music->play(1, MUSIC_NORMAL);
playTitle(0, 10);
+ if (_vm->quit())
+ return !SUCCESS;
playTitle(2, 12);
}
@@ -142,9 +148,9 @@ bool Scene::checkKey() {
while (_vm->_eventMan->pollEvent(event)) {
switch (event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
res = true;
- _vm->shutDown();
break;
case Common::EVENT_KEYDOWN:
// Don't react to modifier keys alone. The original did
@@ -187,7 +193,7 @@ bool Scene::playTitle(int title, int time, int mode) {
_vm->_gfx->getCurrentPal(pal_cut);
- while (!done) {
+ while (!done && !_vm->quit()) {
curTime = _vm->_system->getMillis();
switch (phase) {
diff --git a/engines/saga/itedata.cpp b/engines/saga/itedata.cpp
index 43c3d21012..bbd5cbb615 100644
--- a/engines/saga/itedata.cpp
+++ b/engines/saga/itedata.cpp
@@ -339,7 +339,7 @@ FxTable ITE_SfxTable[ITE_SFXCOUNT] = {
{ 73, 64 }
};
-const char *ITEinterfaceTextStrings[][52] = {
+const char *ITEinterfaceTextStrings[][53] = {
{
// Note that the "Load Successful!" string is never used in ScummVM
"Walk to", "Look At", "Pick Up", "Talk to", "Open",
@@ -358,7 +358,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"There's no opening to close.",
"I don't know how to do that.",
"Show Dialog",
- "What is Rif's reply?"
+ "What is Rif's reply?",
+ "Loading a saved game"
},
// German
{
@@ -378,7 +379,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"Hier ist keine \231ffnung zum Schlie$en.",
"Ich wei$ nicht, wie ich das machen soll.",
"Text zeigen",
- "Wie lautet die Antwort?"
+ "Wie lautet die Antwort?",
+ "Spielstand wird geladen"
},
// Italian fan translation
{
@@ -398,7 +400,8 @@ const char *ITEinterfaceTextStrings[][52] = {
"Nessuna apertura da chiudere.",
"Non saprei come farlo.",
"Dialoghi",
- "Come risponderebbe Rif?"
+ "Come risponderebbe Rif?",
+ "Vuoi davvero caricare il gioco?"
},
// Spanish IHNM
{
@@ -420,7 +423,8 @@ const char *ITEinterfaceTextStrings[][52] = {
NULL,
NULL,
NULL,
- NULL
+ NULL,
+ "Cardango una partida guardada"
}
};
diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h
index 00efd070c1..6d0f5a9d70 100644
--- a/engines/saga/itedata.h
+++ b/engines/saga/itedata.h
@@ -88,7 +88,7 @@ struct FxTable {
extern ObjectTableData ITE_ObjectTable[ITE_OBJECTCOUNT];
extern FxTable ITE_SfxTable[ITE_SFXCOUNT];
-extern const char *ITEinterfaceTextStrings[][52];
+extern const char *ITEinterfaceTextStrings[][53];
#define PUZZLE_PIECES 15
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 732bd0b50c..5bf0c0ec03 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -249,6 +249,8 @@ void MusicPlayer::setVolume(int volume) {
_masterVolume = volume;
+ Common::StackLock lock(_mutex);
+
for (int i = 0; i < 16; ++i) {
if (_channel[i]) {
_channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
@@ -346,7 +348,7 @@ void MusicPlayer::stopMusic() {
}
}
-Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled) : _vm(vm), _mixer(mixer), _enabled(enabled), _adlib(false) {
+Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), _mixer(mixer), _adlib(false) {
_player = new MusicPlayer(driver);
_currentVolume = 0;
@@ -402,7 +404,7 @@ void Music::musicVolumeGauge() {
}
void Music::setVolume(int volume, int time) {
- _targetVolume = volume * 2; // ScummVM has different volume scale
+ _targetVolume = volume;
_currentVolumePercent = 0;
if (volume == -1) // Set Full volume
@@ -432,11 +434,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
uint32 loopStart;
debug(2, "Music::play %d, %d", resourceId, flags);
-
- if (!_enabled) {
- return;
- }
-
+
if (isPlaying() && _trackNumber == resourceId) {
return;
}
@@ -444,11 +442,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
_trackNumber = resourceId;
_player->stopMusic();
_mixer->stopHandle(_musicHandle);
-
- if (!_vm->_musicVolume) {
- return;
- }
-
+
int realTrackNumber;
if (_vm->getGameType() == GType_ITE) {
@@ -591,7 +585,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
_player->_parser = parser;
- setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ setVolume(_vm->_musicVolume);
if (flags & MUSIC_LOOP)
_player->setLoop(true);
@@ -609,7 +603,7 @@ void Music::pause(void) {
}
void Music::resume(void) {
- _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ _player->setVolume(_vm->_musicVolume);
_player->setPlaying(true);
}
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 1953dc6f91..57ff9e0671 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -105,7 +105,7 @@ protected:
class Music {
public:
- Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enabled);
+ Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver);
~Music(void);
void setNativeMT32(bool b) { _player->setNativeMT32(b); }
bool hasNativeMT32() { return _player->hasNativeMT32(); }
@@ -133,7 +133,6 @@ private:
Audio::SoundHandle _musicHandle;
uint32 _trackNumber;
- int _enabled;
bool _adlib;
int _targetVolume;
diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp
index e150caeca5..05b1162973 100644
--- a/engines/saga/rscfile.cpp
+++ b/engines/saga/rscfile.cpp
@@ -121,7 +121,7 @@ bool Resource::loadSagaContext(ResourceContext *context, uint32 contextOffset, u
resourceData->offset = contextOffset + readS1.readUint32();
resourceData->size = readS1.readUint32();
//sanity check
- if ((resourceData->offset > context->file->size()) || (resourceData->size > contextSize)) {
+ if ((resourceData->offset > (uint)context->file->size()) || (resourceData->size > contextSize)) {
result = false;
break;
}
@@ -181,8 +181,8 @@ bool Resource::loadMacContext(ResourceContext *context) {
macDataLength = context->file->readUint32BE();
macMapLength = context->file->readUint32BE();
- if (macDataOffset >= context->file->size() || macMapOffset >= context->file->size() ||
- macDataLength + macMapLength > context->file->size()) {
+ if (macDataOffset >= (uint)context->file->size() || macMapOffset >= (uint)context->file->size() ||
+ macDataLength + macMapLength > (uint)context->file->size()) {
return false;
}
@@ -384,24 +384,24 @@ bool Resource::createContexts() {
if (!soundFileInArray) {
if (_vm->getGameType() == GType_ITE) {
// If the sound file is not specified in the detector table, add it here
- if (Common::File::exists("sounds.rsc") || Common::File::exists("sounds.cmp")) {
+ if (Common::File::exists("sounds.rsc")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("sounds.rsc")) {
- sprintf(soundFileName, "sounds.rsc");
- } else {
- sprintf(soundFileName, "sounds.cmp");
- _vm->_gf_compressed_sounds = true;
- }
- } else if (Common::File::exists("soundsd.rsc") || Common::File::exists("soundsd.cmp")) {
+ sprintf(soundFileName, "sounds.rsc");
+ } else if (Common::File::exists("sounds.cmp")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("soundsd.rsc")) {
- sprintf(soundFileName, "soundsd.rsc");
- } else {
- sprintf(soundFileName, "soundsd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(soundFileName, "sounds.cmp");
+ _vm->_gf_compressed_sounds = true;
+ } else if (Common::File::exists("soundsd.rsc")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "soundsd.rsc");
+ } else if (Common::File::exists("soundsd.cmp")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "soundsd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No sound file found, don't add any file to the array
soundFileInArray = true;
@@ -410,15 +410,15 @@ bool Resource::createContexts() {
}
} else {
// If the sound file is not specified in the detector table, add it here
- if (Common::File::exists("sfx.res") || Common::File::exists("sfx.cmp")) {
+ if (Common::File::exists("sfx.res")) {
_contextsCount++;
soundFileIndex = _contextsCount - 1;
- if (Common::File::exists("sfx.res")) {
- sprintf(soundFileName, "sfx.res");
- } else {
- sprintf(soundFileName, "sfx.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(soundFileName, "sfx.res");
+ } else if (Common::File::exists("sfx.cmp")) {
+ _contextsCount++;
+ soundFileIndex = _contextsCount - 1;
+ sprintf(soundFileName, "sfx.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No sound file found, don't add any file to the array
soundFileInArray = true;
@@ -429,24 +429,24 @@ bool Resource::createContexts() {
if (!voicesFileInArray) {
if (_vm->getGameType() == GType_ITE) {
// If the voices file is not specified in the detector table, add it here
- if (Common::File::exists("voices.rsc") || Common::File::exists("voices.cmp")) {
+ if (Common::File::exists("voices.rsc")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voices.rsc")) {
- sprintf(_voicesFileName[0], "voices.rsc");
- } else {
- sprintf(_voicesFileName[0], "voices.cmp");
- _vm->_gf_compressed_sounds = true;
- }
- } else if (Common::File::exists("voicesd.rsc") || Common::File::exists("voicesd.cmp")) {
+ sprintf(_voicesFileName[0], "voices.rsc");
+ } else if (Common::File::exists("voices.cmp")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voicesd.rsc")) {
- sprintf(_voicesFileName[0], "voicesd.rsc");
- } else {
- sprintf(_voicesFileName[0], "voicesd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(_voicesFileName[0], "voices.cmp");
+ _vm->_gf_compressed_sounds = true;
+ } else if (Common::File::exists("voicesd.rsc")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.rsc");
+ } else if (Common::File::exists("voicesd.cmp")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else if (Common::File::exists("inherit the earth voices") ||
Common::File::exists("inherit the earth voices.cmp")) {
_contextsCount++;
@@ -493,15 +493,15 @@ bool Resource::createContexts() {
sprintf(_voicesFileName[0], "voicess.cmp");
_vm->_gf_compressed_sounds = true;
}
- } else if (Common::File::exists("voicesd.res") || Common::File::exists("voicesd.cmp")) {
+ } else if (Common::File::exists("voicesd.res")) {
_contextsCount++;
voicesFileIndex = _contextsCount - 1;
- if (Common::File::exists("voicesd.res")) {
- sprintf(_voicesFileName[0], "voicesd.res");
- } else {
- sprintf(_voicesFileName[0], "voicesd.cmp");
- _vm->_gf_compressed_sounds = true;
- }
+ sprintf(_voicesFileName[0], "voicesd.res");
+ } else if (Common::File::exists("voicesd.cmp")) {
+ _contextsCount++;
+ voicesFileIndex = _contextsCount - 1;
+ sprintf(_voicesFileName[0], "voicesd.cmp");
+ _vm->_gf_compressed_sounds = true;
} else {
// No voice file found, don't add any file to the array
voicesFileInArray = true;
@@ -521,20 +521,22 @@ bool Resource::createContexts() {
if (_vm->getGameType() == GType_ITE) {
// Check for digital music in ITE
- if (Common::File::exists("music.rsc") || Common::File::exists("music.cmp")) {
+ if (Common::File::exists("music.rsc")) {
_contextsCount++;
digitalMusic = true;
- if (Common::File::exists("music.cmp"))
- sprintf(musicFileName, "music.cmp");
- else
- sprintf(musicFileName, "music.rsc");
- } else if (Common::File::exists("musicd.rsc") || Common::File::exists("musicd.cmp")) {
+ sprintf(musicFileName, "music.rsc");
+ } else if (Common::File::exists("music.cmp")) {
_contextsCount++;
digitalMusic = true;
- if (Common::File::exists("musicd.cmp"))
- sprintf(musicFileName, "musicd.cmp");
- else
- sprintf(musicFileName, "musicd.rsc");
+ sprintf(musicFileName, "music.cmp");
+ } else if (Common::File::exists("musicd.rsc")) {
+ _contextsCount++;
+ digitalMusic = true;
+ sprintf(musicFileName, "musicd.rsc");
+ } else if (Common::File::exists("musicd.cmp")) {
+ _contextsCount++;
+ digitalMusic = true;
+ sprintf(musicFileName, "musicd.cmp");
} else {
digitalMusic = false;
}
@@ -661,9 +663,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
if (chapter < 0)
chapter = (_vm->getGameId() != GID_IHNM_DEMO) ? 8 : 7;
- // TODO
- //if (module.voiceLUT)
- // free module.voiceLUT;
+ _vm->_script->_globalVoiceLUT.freeMem();
// TODO: close chapter context, or rather reassign it in our case
@@ -769,7 +769,6 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
_vm->_sprite->_mainSprites.freeMem();
_vm->_sprite->loadList(_metaResource.mainSpritesID, _vm->_sprite->_mainSprites);
-
_vm->_actor->loadObjList(_metaResource.objectCount, _metaResource.objectsResourceID);
_vm->_resource->loadResource(resourceContext, _metaResource.cutawayListResourceID, resourcePointer, resourceLength);
@@ -805,49 +804,21 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
free(resourcePointer);
} else {
// The IHNM demo has a fixed music track and doesn't load a song table
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(3, MUSIC_LOOP);
free(resourcePointer);
}
int voiceLUTResourceID = 0;
- _vm->_script->_globalVoiceLUT.freeMem();
-
- switch (chapter) {
- case 1:
- _vm->_sndRes->setVoiceBank(1);
- voiceLUTResourceID = 23;
- break;
- case 2:
- _vm->_sndRes->setVoiceBank(2);
- voiceLUTResourceID = 24;
- break;
- case 3:
- _vm->_sndRes->setVoiceBank(3);
- voiceLUTResourceID = 25;
- break;
- case 4:
- _vm->_sndRes->setVoiceBank(4);
- voiceLUTResourceID = 26;
- break;
- case 5:
- _vm->_sndRes->setVoiceBank(5);
- voiceLUTResourceID = 27;
- break;
- case 6:
- _vm->_sndRes->setVoiceBank(6);
- voiceLUTResourceID = 28;
- break;
- case 7:
+ if (chapter != 7) {
+ int voiceBank = (chapter == 8) ? 0 : chapter;
+ _vm->_sndRes->setVoiceBank(voiceBank);
+ voiceLUTResourceID = 22 + voiceBank;
+ } else {
// IHNM demo
_vm->_sndRes->setVoiceBank(0);
voiceLUTResourceID = 17;
- break;
- case 8:
- _vm->_sndRes->setVoiceBank(0);
- voiceLUTResourceID = 22;
- break;
}
if (voiceLUTResourceID) {
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index fafbd02cec..5ce5d6ab93 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -64,7 +64,6 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
_leftMouseButtonPressed = _rightMouseButtonPressed = false;
_console = NULL;
- _quit = false;
_resource = NULL;
_sndRes = NULL;
@@ -93,20 +92,20 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
// The Linux version of Inherit the Earth puts all data files in an
// 'itedata' sub-directory, except for voices.rsc
- Common::File::addDefaultDirectory(_gameDataPath + "itedata/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("itedata"));
// The Windows version of Inherit the Earth puts various data files in
// other subdirectories.
- Common::File::addDefaultDirectory(_gameDataPath + "graphics/");
- Common::File::addDefaultDirectory(_gameDataPath + "music/");
- Common::File::addDefaultDirectory(_gameDataPath + "sound/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("graphics"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("music"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("sound"));
// The Multi-OS version puts the voices file in the root directory of
// the CD. The rest of the data files are in game/itedata
- Common::File::addDefaultDirectory(_gameDataPath + "game/itedata/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("game").getChild("itedata"));
// Mac CD Wyrmkeep
- Common::File::addDefaultDirectory(_gameDataPath + "patch/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("patch"));
_displayClip.left = _displayClip.top = 0;
syst->getEventManager()->registerRandomSource(_rnd, "saga");
@@ -142,8 +141,7 @@ SagaEngine::~SagaEngine() {
}
int SagaEngine::init() {
- _soundVolume = ConfMan.getInt("sfx_volume") / 25;
- _musicVolume = ConfMan.getInt("music_volume") / 25;
+ _musicVolume = ConfMan.getInt("music_volume");
_subtitlesEnabled = ConfMan.getBool("subtitles");
_readingSpeed = getTalkspeed();
_copyProtection = ConfMan.getBool("copy_protection");
@@ -194,29 +192,21 @@ int SagaEngine::init() {
if (native_mt32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _music = new Music(this, _mixer, _driver, _musicVolume);
+ _music = new Music(this, _mixer, _driver);
_music->setNativeMT32(native_mt32);
_music->setAdlib(adlib);
-
- if (!_musicVolume) {
- debug(1, "Music disabled.");
- }
-
_render = new Render(this, _system);
if (!_render->initialized()) {
return FAILURE;
}
// Initialize system specific sound
- _sound = new Sound(this, _mixer, _soundVolume);
- if (!_soundVolume) {
- debug(1, "Sound disabled.");
- }
-
+ _sound = new Sound(this, _mixer);
+
_interface->converseInit();
_script->setVerb(_script->getVerbType(kVerbWalkTo));
- _music->setVolume(-1, 1);
+ _music->setVolume(_musicVolume, 1);
_gfx->initPalette();
@@ -233,6 +223,8 @@ int SagaEngine::init() {
}
}
+ syncSoundSettings();
+
// FIXME: This is the ugly way of reducing redraw overhead. It works
// well for 320x200 but it's unclear how well it will work for
// 640x480.
@@ -255,14 +247,22 @@ int SagaEngine::go() {
_interface->addToInventory(_actor->objIndexToId(0)); // Magic hat
_scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade);
} else if (ConfMan.hasKey("save_slot")) {
+ // Init the current chapter to 8 (character selection) for IHNM
+ if (getGameType() == GType_IHNM)
+ _scene->changeScene(-2, 0, kTransitionFade, 8);
+
// First scene sets up palette
_scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade);
_events->handleEvents(0); // Process immediate events
- _interface->setMode(kPanelMain);
- char *fileName;
- fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
+ if (getGameType() != GType_IHNM)
+ _interface->setMode(kPanelMain);
+ else
+ _interface->setMode(kPanelChapterSelection);
+
+ char *fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
load(fileName);
+ syncSoundSettings();
} else {
_framesEsc = 0;
_scene->startScene();
@@ -270,7 +270,7 @@ int SagaEngine::go() {
uint32 currentTicks;
- while (!_quit) {
+ while (!quit()) {
if (_console->isAttached())
_console->onFrame();
@@ -520,4 +520,16 @@ int SagaEngine::getTalkspeed() {
return (ConfMan.getInt("talkspeed") * 3 + 255 / 2) / 255;
}
+void SagaEngine::syncSoundSettings() {
+ _subtitlesEnabled = ConfMan.getBool("subtitles");
+ _readingSpeed = getTalkspeed();
+
+ if (_readingSpeed > 3)
+ _readingSpeed = 0;
+
+ _musicVolume = ConfMan.getInt("music_volume");
+ _music->setVolume(_musicVolume, 1);
+ _sound->setVolume();
+}
+
} // End of namespace Saga
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 6b6eb6b3fb..0b6b3b1478 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -295,7 +295,8 @@ enum TextStringIds {
kTextVoices,
kTextText,
kTextAudio,
- kTextBoth
+ kTextBoth,
+ kTextLoadSavedGame
};
struct GameResourceDescription {
@@ -491,7 +492,6 @@ protected:
public:
SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc);
virtual ~SagaEngine();
- void shutDown() { _quit = true; }
void save(const char *fileName, const char *saveName);
void load(const char *fileName);
@@ -512,6 +512,8 @@ public:
return isSaveListFull() ? _saveFilesCount : _saveFilesCount + 1;
}
+ virtual void syncSoundSettings();
+
int16 _framesEsc;
uint32 _globalFlags;
@@ -520,6 +522,7 @@ public:
int _soundVolume;
int _musicVolume;
+ int _speechVolume;
bool _subtitlesEnabled;
bool _voicesEnabled;
bool _voiceFilesExist;
@@ -610,8 +613,6 @@ public:
bool _rightMouseButtonPressed;
int _mouseClickCount;
- bool _quit;
-
//current game description
int _gameNumber;
const SAGAGameDescription *_gameDescription;
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index c3c1587822..074b4c933a 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -315,7 +315,7 @@ void Scene::creditsScene() {
break;
}
- _vm->shutDown();
+ _vm->quitGame();
return;
}
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index ea61f5ce04..e19fd5ae02 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -276,31 +276,14 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {
if (obj->_sceneNumber != ITE_SCENE_INV) {
obj->_sceneNumber = ITE_SCENE_INV;
- // WORKAROUND for a problematic object in IHNM
- // There are 3 different scenes in front of the zeppelin, in Gorrister's chapter. A scene where the
- // zeppelin is in the air (scene 17), a scene where it approaches Gorrister's (scene 16) and another one
- // where it has landed (scene 18).
- // In two of these scenes (the "on air" and "approaching" ones), when the player uses the knife with the
- // rope, the associated script picks up object id 16392. In the "zeppelin landed" scene (scene 18), the
- // associated script picks up object id 16390. This seems to be a script bug, as it should be id 16392,
- // like in the other two scenes, as it is the same object (the rope). Picking up object 16390 leads to an
- // assertion anyway, therefore we change the problematic object (16390) to the correct one (16392) here.
- // Fixes bug #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring"
- if (_vm->getGameType() == GType_IHNM) {
- if (_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 18) {
- if (objectId == 16390)
- objectId = 16392;
- }
- }
-
- // WORKAROUND for two incorrect object sprites in the IHNM demo
- // (the mirror and the icon in Ted's part). Set them correctly here
- if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (objectId == 16408)
- obj->_spriteListResourceId = 24;
- if (objectId == 16409)
- obj->_spriteListResourceId = 25;
- }
+ // Normally, when objects are picked up, they should always have the same
+ // _spriteListResourceId as their _index value. Some don't in IHNM, so
+ // we fix their sprite here
+ // Fixes bugs #2057200 - "IHNM: Invisible inventory objects",
+ // #1861126 - "IHNM: Crash when Gorrister cuts sheet in the mooring ring"
+ // and some incorrect objects in the IHNM demo
+ if (_vm->getGameType() == GType_IHNM)
+ obj->_spriteListResourceId = obj->_index;
_vm->_interface->addToInventory(objectId);
}
@@ -356,7 +339,7 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) {
// exit the game. Known non-interactive demos are GID_ITE_MACDEMO1 and
// GID_ITE_WINDEMO1
if (_vm->getFeatures() & GF_NON_INTERACTIVE)
- _vm->shutDown();
+ _vm->quitGame();
}
// Script function #6 (0x06) blocking
@@ -572,7 +555,7 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
}
if (_vm->getGameType() == GType_ITE && sceneNumber < 0) {
- _vm->shutDown();
+ _vm->quitGame();
return;
}
@@ -1482,7 +1465,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop() + 9;
if (param >= 9 && param <= 34) {
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(param);
} else {
_vm->_music->stop();
@@ -1499,7 +1482,7 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
if (param1 >= _vm->_music->_songTableLen) {
warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
} else {
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL);
if (!_vm->_scene->haveChapterPointsChanged()) {
_vm->_scene->setCurrentMusicTrack(param1);
@@ -1945,7 +1928,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
if (param1 >= _vm->_music->_songTableLen) {
warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
} else {
- _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ _vm->_music->setVolume(_vm->_musicVolume, 1);
event.type = kEvTOneshot;
event.code = kMusicEvent;
event.param = _vm->_music->_songTable[param1];
diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp
index 8d269fb3e8..b990b8ddf7 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -169,7 +169,6 @@ void SndRes::playVoice(uint32 resourceId) {
}
bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) {
- byte *soundResource;
Audio::AudioStream *voxStream;
size_t soundResourceLength;
bool result = false;
@@ -180,13 +179,13 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
byte flags;
size_t voxSize;
const GameSoundInfo *soundInfo;
+ Common::File* file;
if (resourceId == (uint32)-1) {
return false;
}
if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) {
- Common::File soundFile;
char soundFileName[40];
int dirIndex = resourceId / 64;
@@ -199,15 +198,23 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
} else {
sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId);
}
- soundFile.open(soundFileName);
- soundResourceLength = soundFile.size();
- soundResource = new byte[soundResourceLength];
- soundFile.read(soundResource, soundResourceLength);
- soundFile.close();
+
+ file = new Common::File();
+
+ file->open(soundFileName);
+ soundResourceLength = file->size();
} else {
- _vm->_resource->loadResource(context, resourceId, soundResource, soundResourceLength);
+
+ ResourceData* resourceData = _vm->_resource->getResourceData(context, resourceId);
+ file = context->getFile(resourceData);
+
+ file->seek(resourceData->offset);
+ soundResourceLength = resourceData->size;
+
}
+ Common::SeekableReadStream& readS = *file;
+
if ((context->fileType & GAME_VOICEFILE) != 0) {
soundInfo = _vm->getVoiceInfo();
} else {
@@ -220,16 +227,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
context->table[resourceId].fillSoundPatch(soundInfo);
}
- MemoryReadStream readS(soundResource, soundResourceLength);
resourceType = soundInfo->resourceType;
if (soundResourceLength >= 8) {
- if (!memcmp(soundResource, "Creative", 8)) {
+ byte header[8];
+
+ readS.read(&header, 8);
+ readS.seek(readS.pos() - 8);
+
+ if (!memcmp(header, "Creative", 8)) {
resourceType = kSoundVOC;
- } else if (!memcmp(soundResource, "RIFF", 4) != 0) {
+ } else if (!memcmp(header, "RIFF", 4) != 0) {
resourceType = kSoundWAV;
- } else if (!memcmp(soundResource, "FORM", 4) != 0) {
+ } else if (!memcmp(header, "FORM", 4) != 0) {
resourceType = kSoundAIFF;
}
@@ -244,11 +255,11 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
uncompressedSound = true;
if ((_vm->getFeatures() & GF_COMPRESSED_SOUNDS) && !uncompressedSound) {
- if (soundResource[0] == char(0)) {
+ if (header[0] == char(0)) {
resourceType = kSoundMP3;
- } else if (soundResource[0] == char(1)) {
+ } else if (header[0] == char(1)) {
resourceType = kSoundOGG;
- } else if (soundResource[0] == char(2)) {
+ } else if (header[0] == char(2)) {
resourceType = kSoundFLAC;
}
}
@@ -268,9 +279,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.stereo = false;
if (onlyHeader) {
buffer.buffer = NULL;
- free(soundResource);
} else {
- buffer.buffer = soundResource;
+ buffer.buffer = (byte *) malloc(soundResourceLength);
+ readS.read(buffer.buffer, soundResourceLength);
}
result = true;
break;
@@ -284,9 +295,10 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.buffer = NULL;
} else {
buffer.buffer = (byte *)malloc(buffer.size);
- memcpy(buffer.buffer, soundResource + 36, buffer.size);
+
+ readS.seek(readS.pos() + 36);
+ readS.read(buffer.buffer, buffer.size);
}
- free(soundResource);
result = true;
break;
case kSoundVOX:
@@ -297,7 +309,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.size = soundResourceLength * 4;
if (onlyHeader) {
buffer.buffer = NULL;
- free(soundResource);
} else {
voxStream = Audio::makeADPCMStream(&readS, false, soundResourceLength, Audio::kADPCMOki);
buffer.buffer = (byte *)malloc(buffer.size);
@@ -325,7 +336,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundWAV:
if (Audio::loadWAVFromStream(readS, size, rate, flags)) {
@@ -342,7 +352,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundAIFF:
if (Audio::loadAIFFFromStream(readS, size, rate, flags)) {
@@ -359,7 +368,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
result = true;
}
- free(soundResource);
break;
case kSoundMP3:
case kSoundOGG:
@@ -382,12 +390,17 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
buffer.buffer = NULL;
result = true;
- free(soundResource);
break;
default:
error("SndRes::load Unknown sound type");
}
+
+ if (_vm->getGameType() == GType_IHNM && _vm->isMacResources()) {
+ delete file;
+ }
+
+
// In ITE CD De some voices are absent and contain just 5 bytes header
// Round it to even number so soundmanager will not crash.
// See bug #1256701
diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h
index e77c833076..d5507ebc55 100644
--- a/engines/saga/sndres.h
+++ b/engines/saga/sndres.h
@@ -39,7 +39,6 @@ public:
SndRes(SagaEngine *vm);
~SndRes();
- int loadSound(uint32 resourceId);
void playSound(uint32 resourceId, int volume, bool loop);
void playVoice(uint32 resourceId);
int getVoiceLength(uint32 resourceId);
diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp
index 1d3263d302..1d41d39cf2 100644
--- a/engines/saga/sound.cpp
+++ b/engines/saga/sound.cpp
@@ -22,8 +22,10 @@
* $Id$
*
*/
-#include "saga/saga.h"
+#include "common/config-manager.h"
+
+#include "saga/saga.h"
#include "saga/sound.h"
#include "sound/audiostream.h"
@@ -32,13 +34,13 @@
namespace Saga {
-Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume) :
+Sound::Sound(SagaEngine *vm, Audio::Mixer *mixer) :
_vm(vm), _mixer(mixer), _voxStream(0) {
for (int i = 0; i < SOUND_HANDLES; i++)
_handles[i].type = kFreeHandle;
- setVolume(volume == 10 ? 255 : volume * 25);
+ setVolume();
}
Sound::~Sound() {
@@ -61,7 +63,8 @@ SndHandle *Sound::getHandle() {
return NULL;
}
-void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop) {
+void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume,
+ sndHandleType handleType, bool loop) {
byte flags;
flags = Audio::Mixer::FLAG_AUTOFREE;
@@ -81,7 +84,12 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int
flags |= Audio::Mixer::FLAG_UNSIGNED;
if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) {
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume);
+ if (handleType == kVoiceHandle)
+ _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
+ else
+ _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
} else {
Audio::AudioStream *stream = NULL;
MemoryReadStream *tmp = NULL;
@@ -116,12 +124,23 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int
#endif
default:
// No compression, play it as raw sound
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume);
+ if (handleType == kVoiceHandle)
+ _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
+ else
+ _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, flags, -1, volume);
break;
}
- if (stream != NULL)
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1, volume, 0, true, false);
+ if (stream != NULL) {
+ if (handleType == kVoiceHandle)
+ _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, handle, stream, -1,
+ volume, 0, true, false);
+ else
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1,
+ volume, 0, true, false);
+ }
}
}
@@ -129,7 +148,7 @@ void Sound::playSound(SoundBuffer &buffer, int volume, bool loop) {
SndHandle *handle = getHandle();
handle->type = kEffectHandle;
- playSoundBuffer(&handle->handle, buffer, 2 * volume, loop);
+ playSoundBuffer(&handle->handle, buffer, 2 * volume, handle->type, loop);
}
void Sound::pauseSound() {
@@ -156,7 +175,7 @@ void Sound::playVoice(SoundBuffer &buffer) {
SndHandle *handle = getHandle();
handle->type = kVoiceHandle;
- playSoundBuffer(&handle->handle, buffer, 255, false);
+ playSoundBuffer(&handle->handle, buffer, 255, handle->type, false);
}
void Sound::pauseVoice() {
@@ -184,9 +203,11 @@ void Sound::stopAll() {
stopSound();
}
-void Sound::setVolume(int volume) {
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
- _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
+void Sound::setVolume() {
+ _vm->_soundVolume = ConfMan.getInt("sound_volume");
+ _vm->_speechVolume = ConfMan.getInt("speech_volume");
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _vm->_soundVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _vm->_speechVolume);
}
} // End of namespace Saga
diff --git a/engines/saga/sound.h b/engines/saga/sound.h
index ce479c64d1..6d9e42a49d 100644
--- a/engines/saga/sound.h
+++ b/engines/saga/sound.h
@@ -71,7 +71,7 @@ struct SndHandle {
class Sound {
public:
- Sound(SagaEngine *vm, Audio::Mixer *mixer, int volume);
+ Sound(SagaEngine *vm, Audio::Mixer *mixer);
~Sound();
void playSound(SoundBuffer &buffer, int volume, bool loop);
@@ -86,11 +86,12 @@ public:
void stopAll();
- void setVolume(int volume);
+ void setVolume();
private:
- void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume, bool loop);
+ void playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume,
+ sndHandleType handleType, bool loop);
SndHandle *getHandle();
diff --git a/engines/saga/sprite.cpp b/engines/saga/sprite.cpp
index be4f2a423d..a1f78e1b9f 100644
--- a/engines/saga/sprite.cpp
+++ b/engines/saga/sprite.cpp
@@ -74,9 +74,11 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
Sprite::~Sprite(void) {
debug(8, "Shutting down sprite subsystem...");
_mainSprites.freeMem();
- _inventorySprites.freeMem();
- _arrowSprites.freeMem();
- _saveReminderSprites.freeMem();
+ if (_vm->getGameType() == GType_IHNM) {
+ _inventorySprites.freeMem();
+ _arrowSprites.freeMem();
+ _saveReminderSprites.freeMem();
+ }
free(_decodeBuf);
}
@@ -410,6 +412,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
while (!readS.eos() && (outPointer < outPointerEnd)) {
bg_runcount = readS.readByte();
+ if (readS.eos())
+ break;
fg_runcount = readS.readByte();
for (c = 0; c < bg_runcount && !readS.eos(); c++) {
@@ -422,6 +426,8 @@ void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t ou
for (c = 0; c < fg_runcount && !readS.eos(); c++) {
*outPointer = readS.readByte();
+ if (readS.eos())
+ break;
if (outPointer < outPointerEnd)
outPointer++;
else
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index df6660523a..b2bb8be9c9 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -50,9 +50,11 @@ Actor::Actor(ScummEngine *scumm, int id) :
assert(_vm != 0);
}
-void Actor::initActor(int mode) {
- // begin HE specific
+void ActorHE::initActor(int mode) {
+ Actor::initActor(mode);
+
if (mode == -1) {
+ _heOffsX = _heOffsY = 0;
_heSkipLimbs = false;
memset(_heTalkQueue, 0, sizeof(_heTalkQueue));
}
@@ -70,11 +72,18 @@ void Actor::initActor(int mode) {
_hePaletteNum = 0;
_heFlags = 0;
_heTalking = false;
- // end HE specific
+ if (_vm->_game.heversion >= 61)
+ _flip = 0;
+
+ _clipOverride = _vm->_actorClipOverride;
+
+ _auxBlock.reset();
+}
+
+void Actor::initActor(int mode) {
if (mode == -1) {
- _offsX = _offsY = 0;
_top = _bottom = 0;
_needRedraw = false;
_needBgReset = false;
@@ -132,9 +141,6 @@ void Actor::initActor(int mode) {
_forceClip = (_vm->_game.version >= 7) ? 100 : 0;
_ignoreTurns = false;
- if (_vm->_game.heversion >= 61)
- _flip = 0;
-
_talkFrequency = 256;
_talkPan = 64;
_talkVolume = 127;
@@ -148,10 +154,6 @@ void Actor::initActor(int mode) {
_walkScript = 0;
_talkScript = 0;
- _clipOverride = _vm->_actorClipOverride;
-
- _auxBlock.reset();
-
_vm->_classData[_number] = (_vm->_game.version >= 7) ? _vm->_classData[0] : 0;
}
@@ -879,9 +881,9 @@ void Actor::putActor(int dstX, int dstY, int newRoom) {
_vm->stopTalk();
}
- // WORKAROUND: The green transparency of the tank in the Hall of Oddities is
- // is positioned one pixel too far to the left. This appears to be a
- // bug in the original game as well.
+ // WORKAROUND: The green transparency of the tank in the Hall of Oddities
+ // is positioned one pixel too far to the left. This appears to be a bug
+ // in the original game as well.
if (_vm->_game.id == GID_SAMNMAX && newRoom == 16 && _number == 5 && dstX == 235 && dstY == 236)
dstX++;
@@ -904,7 +906,7 @@ void Actor::putActor(int dstX, int dstY, int newRoom) {
} else {
#ifdef ENABLE_HE
if (_vm->_game.heversion >= 71)
- ((ScummEngine_v71he *)_vm)->queueAuxBlock(this);
+ ((ScummEngine_v71he *)_vm)->queueAuxBlock((ActorHE *)this);
#endif
hideActor();
}
@@ -1208,6 +1210,10 @@ void Actor::hideActor() {
_cost.soundCounter = 0;
_needRedraw = false;
_needBgReset = true;
+}
+
+void ActorHE::hideActor() {
+ Actor::hideActor();
_auxBlock.reset();
}
@@ -1434,39 +1440,28 @@ void Actor::drawActorCostume(bool hitTestMode) {
}
setupActorScale();
+
+ BaseCostumeRenderer *bcr = _vm->_costumeRenderer;
+ prepareDrawActorCostume(bcr);
- BaseCostumeRenderer* bcr = _vm->_costumeRenderer;
-
- bcr->_actorID = _number;
-
- bcr->_actorX = _pos.x + _offsX;
- bcr->_actorY = _pos.y + _offsY - _elevation;
-
- if (_vm->_game.version <= 2) {
- bcr->_actorX *= V12_X_MULTIPLIER;
- bcr->_actorY *= V12_Y_MULTIPLIER;
+ // If the actor is partially hidden, redraw it next frame.
+ if (bcr->drawCostume(_vm->_virtscr[kMainVirtScreen], _vm->_gdi->_numStrips, this, _drawToBackBuf) & 1) {
+ _needRedraw = (_vm->_game.version <= 6);
}
- bcr->_actorX -= _vm->_virtscr[kMainVirtScreen].xstart;
- if (_vm->_game.platform == Common::kPlatformNES) {
- // In the NES version, when the actor is facing right,
- // we need to shift it 8 pixels to the left
- if (_facing == 90)
- bcr->_actorX -= 8;
- } else if (_vm->_game.version <= 2) {
- // HACK: We have to adjust the x position by one strip (8 pixels) in
- // V2 games. However, it is not quite clear to me why. And to fully
- // match the original, it seems we have to offset by 2 strips if the
- // actor is facing left (270 degree).
- // V1 games are once again slightly different, here we only have
- // to adjust the 270 degree case...
- if (_facing == 270)
- bcr->_actorX += 16;
- else if (_vm->_game.version == 2)
- bcr->_actorX += 8;
+ if (!hitTestMode) {
+ // Record the vertical extent of the drawn actor
+ _top = bcr->_draw_top;
+ _bottom = bcr->_draw_bottom;
}
+}
- bcr->_clipOverride = _clipOverride;
+
+void Actor::prepareDrawActorCostume(BaseCostumeRenderer *bcr) {
+
+ bcr->_actorID = _number;
+ bcr->_actorX = _pos.x - _vm->_virtscr[kMainVirtScreen].xstart;
+ bcr->_actorY = _pos.y - _elevation;
if (_vm->_game.version == 4 && (_boxscale & 0x8000)) {
bcr->_scaleX = bcr->_scaleY = _vm->getScaleFromSlot((_boxscale & 0x7fff) + 1, _pos.x, _pos.y);
@@ -1478,8 +1473,6 @@ void Actor::drawActorCostume(bool hitTestMode) {
bcr->_shadow_mode = _shadowMode;
if (_vm->_game.version >= 5 && _vm->_game.heversion == 0) {
bcr->_shadow_table = _vm->_shadowPalette;
- } else if (_vm->_game.heversion == 70) {
- bcr->_shadow_table = _vm->_HEV7ActorPalette;
}
bcr->setCostume(_costume, _heXmapNum);
@@ -1510,6 +1503,19 @@ void Actor::drawActorCostume(bool hitTestMode) {
bcr->_draw_top = 0x7fffffff;
bcr->_draw_bottom = 0;
+}
+
+void ActorHE::prepareDrawActorCostume(BaseCostumeRenderer *bcr) {
+ Actor::prepareDrawActorCostume(bcr);
+
+ bcr->_actorX += _heOffsX;
+ bcr->_actorY += _heOffsY;
+
+ bcr->_clipOverride = _clipOverride;
+
+ if (_vm->_game.heversion == 70) {
+ bcr->_shadow_table = _vm->_HEV7ActorPalette;
+ }
bcr->_skipLimbs = (_heSkipLimbs != 0);
bcr->_paletteNum = _hePaletteNum;
@@ -1530,16 +1536,36 @@ void Actor::drawActorCostume(bool hitTestMode) {
}
}
_heNoTalkAnimation = 0;
+}
- // If the actor is partially hidden, redraw it next frame.
- if (bcr->drawCostume(_vm->_virtscr[kMainVirtScreen], _vm->_gdi->_numStrips, this, _drawToBackBuf) & 1) {
- _needRedraw = (_vm->_game.version <= 6);
+void Actor_v2::prepareDrawActorCostume(BaseCostumeRenderer *bcr) {
+ Actor::prepareDrawActorCostume(bcr);
+
+ bcr->_actorX = _pos.x;
+ bcr->_actorY = _pos.y - _elevation;
+
+ if (_vm->_game.version <= 2) {
+ bcr->_actorX *= V12_X_MULTIPLIER;
+ bcr->_actorY *= V12_Y_MULTIPLIER;
}
+ bcr->_actorX -= _vm->_virtscr[kMainVirtScreen].xstart;
- if (!hitTestMode) {
- // Record the vertical extent of the drawn actor
- _top = bcr->_draw_top;
- _bottom = bcr->_draw_bottom;
+ if (_vm->_game.platform == Common::kPlatformNES) {
+ // In the NES version, when the actor is facing right,
+ // we need to shift it 8 pixels to the left
+ if (_facing == 90)
+ bcr->_actorX -= 8;
+ } else if (_vm->_game.version <= 2) {
+ // HACK: We have to adjust the x position by one strip (8 pixels) in
+ // V2 games. However, it is not quite clear to me why. And to fully
+ // match the original, it seems we have to offset by 2 strips if the
+ // actor is facing left (270 degree).
+ // V1 games are once again slightly different, here we only have
+ // to adjust the 270 degree case...
+ if (_facing == 270)
+ bcr->_actorX += 16;
+ else if (_vm->_game.version == 2)
+ bcr->_actorX += 8;
}
}
@@ -1611,13 +1637,15 @@ void Actor::startAnimActor(int f) {
if (isInCurrentRoom() && _costume != 0) {
_animProgress = 0;
- _cost.animCounter = 0;
_needRedraw = true;
+ _cost.animCounter = 0;
// V1 - V2 games don't seem to need a _cost.reset() at this point.
// Causes Zak to lose his body in several scenes, see bug #771508
if (_vm->_game.version >= 3 && f == _initFrame) {
_cost.reset();
- _auxBlock.reset();
+ if (_vm->_game.heversion != 0) {
+ ((ActorHE *)this)->_auxBlock.reset();
+ }
}
_vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1);
_frame = f;
@@ -1758,7 +1786,7 @@ void ScummEngine::resetActorBgs() {
clearGfxUsageBit(strip, USAGE_BIT_DIRTY);
clearGfxUsageBit(strip, USAGE_BIT_RESTORED);
for (j = 1; j < _numActors; j++) {
- if (_actors[j]->_heFlags & 1)
+ if (_game.heversion != 0 && ((ActorHE *)_actors[j])->_heFlags & 1)
continue;
if (testGfxUsageBit(strip, j) &&
@@ -1776,7 +1804,7 @@ void ScummEngine::resetActorBgs() {
}
// HE specific
-void Actor::drawActorToBackBuf(int x, int y) {
+void ActorHE::drawActorToBackBuf(int x, int y) {
int curTop = _top;
int curBottom = _bottom;
@@ -1936,7 +1964,8 @@ void ScummEngine::actorTalk(const byte *msg) {
stopTalk();
}
setTalkingActor(a->_number);
- a->_heTalking = true;
+ if (_game.heversion != 0)
+ ((ActorHE *)a)->_heTalking = true;
if (!_string[0].no_talk_anim) {
a->runActorTalkScript(a->_talkStartFrame);
_useTalkAnims = true;
@@ -2009,7 +2038,8 @@ void ScummEngine::stopTalk() {
}
if (_game.version <= 7 && _game.heversion == 0)
setTalkingActor(0xFF);
- a->_heTalking = false;
+ if (_game.heversion != 0)
+ ((ActorHE *)a)->_heTalking = false;
}
if (_game.id == GID_DIG || _game.id == GID_CMI) {
@@ -2035,9 +2065,7 @@ void ScummEngine::stopTalk() {
#pragma mark -
-void Actor::setActorCostume(int c) {
- int i;
-
+void ActorHE::setActorCostume(int c) {
if (_vm->_game.heversion >= 61 && (c == -1 || c == -2)) {
_heSkipLimbs = (c == -1);
_needRedraw = true;
@@ -2049,27 +2077,43 @@ void Actor::setActorCostume(int c) {
if (_vm->_game.heversion == 61)
c &= 0xff;
- _costumeNeedsInit = true;
-
if (_vm->_game.features & GF_NEW_COSTUMES) {
- memset(_animVariable, 0, sizeof(_animVariable));
-
#ifdef ENABLE_HE
if (_vm->_game.heversion >= 71)
((ScummEngine_v71he *)_vm)->queueAuxBlock(this);
#endif
+ _auxBlock.reset();
+ if (_visible) {
+ if (_vm->_game.heversion >= 60)
+ _needRedraw = true;
+ }
+ }
+
+ Actor::setActorCostume(c);
+
+ if (_vm->_game.heversion >= 71 && _vm->getTalkingActor() == _number) {
+ if (_vm->_game.heversion <= 95 || (_vm->_game.heversion >= 98 && _vm->VAR(_vm->VAR_SKIP_RESET_TALK_ACTOR) == 0)) {
+ _vm->setTalkingActor(0);
+ }
+ }
+}
+
+void Actor::setActorCostume(int c) {
+ int i;
+
+ _costumeNeedsInit = true;
+
+ if (_vm->_game.features & GF_NEW_COSTUMES) {
+ memset(_animVariable, 0, sizeof(_animVariable));
_costume = c;
_cost.reset();
- _auxBlock.reset();
if (_visible) {
if (_costume) {
_vm->ensureResourceLoaded(rtCostume, _costume);
}
startAnimActor(_initFrame);
- if (_vm->_game.heversion >= 60)
- _needRedraw = true;
}
} else {
if (_visible) {
@@ -2104,12 +2148,6 @@ void Actor::setActorCostume(int c) {
for (i = 0; i < 32; i++)
_palette[i] = 0xFF;
}
-
- if (_vm->_game.heversion >= 71 && _vm->getTalkingActor() == _number) {
- if (_vm->_game.heversion <= 95 || (_vm->_game.heversion >= 98 && _vm->VAR(_vm->VAR_SKIP_RESET_TALK_ACTOR) == 0)) {
- _vm->setTalkingActor(0);
- }
- }
}
static const char* v0ActorNames[7] = {
@@ -2245,7 +2283,7 @@ bool Actor_v2::isPlayer() {
return _vm->VAR(42) <= _number && _number <= _vm->VAR(43);
}
-void Actor::setHEFlag(int bit, int set) {
+void ActorHE::setHEFlag(int bit, int set) {
// Note that condition is inverted
if (!set) {
_heFlags |= bit;
@@ -2254,7 +2292,7 @@ void Actor::setHEFlag(int bit, int set) {
}
}
-void Actor::setUserCondition(int slot, int set) {
+void ActorHE::setUserCondition(int slot, int set) {
const int condMaskCode = (_vm->_game.heversion >= 85) ? 0x1FFF : 0x3FF;
assertRange(1, slot, 32, "setUserCondition: Condition");
if (set == 0) {
@@ -2269,12 +2307,12 @@ void Actor::setUserCondition(int slot, int set) {
}
}
-bool Actor::isUserConditionSet(int slot) const {
+bool ActorHE::isUserConditionSet(int slot) const {
assertRange(1, slot, 32, "isUserConditionSet: Condition");
return (_heCondMask & (1 << (slot + 0xF))) != 0;
}
-void Actor::setTalkCondition(int slot) {
+void ActorHE::setTalkCondition(int slot) {
const int condMaskCode = (_vm->_game.heversion >= 85) ? 0x1FFF : 0x3FF;
assertRange(1, slot, 32, "setTalkCondition: Condition");
_heCondMask = (_heCondMask & ~condMaskCode) | 1;
@@ -2288,7 +2326,7 @@ void Actor::setTalkCondition(int slot) {
}
}
-bool Actor::isTalkConditionSet(int slot) const {
+bool ActorHE::isTalkConditionSet(int slot) const {
assertRange(1, slot, 32, "isTalkConditionSet: Condition");
return (_heCondMask & (1 << (slot - 1))) != 0;
}
@@ -2311,10 +2349,10 @@ void ScummEngine_v71he::postProcessAuxQueue() {
for (int i = 0; i < _auxEntriesNum; ++i) {
AuxEntry *ae = &_auxEntries[i];
if (ae->actorNum != -1) {
- Actor *a = derefActor(ae->actorNum, "postProcessAuxQueue");
+ ActorHE *a = (ActorHE *)derefActor(ae->actorNum, "postProcessAuxQueue");
const uint8 *cost = getResourceAddress(rtCostume, a->_costume);
- int dy = a->_offsY + a->getPos().y;
- int dx = a->_offsX + a->getPos().x;
+ int dy = a->_heOffsY + a->getPos().y;
+ int dx = a->_heOffsX + a->getPos().x;
if (_game.heversion >= 72)
dy -= a->getElevation();
@@ -2378,7 +2416,7 @@ void ScummEngine_v71he::postProcessAuxQueue() {
_auxEntriesNum = 0;
}
-void ScummEngine_v71he::queueAuxBlock(Actor *a) {
+void ScummEngine_v71he::queueAuxBlock(ActorHE *a) {
if (!a->_auxBlock.visible)
return;
@@ -2401,8 +2439,8 @@ void Actor::saveLoadWithSerializer(Serializer *ser) {
static const SaveLoadEntry actorEntries[] = {
MKLINE(Actor, _pos.x, sleInt16, VER(8)),
MKLINE(Actor, _pos.y, sleInt16, VER(8)),
- MKLINE(Actor, _offsX, sleInt16, VER(32)),
- MKLINE(Actor, _offsY, sleInt16, VER(32)),
+ MKLINE(Actor, _heOffsX, sleInt16, VER(32)),
+ MKLINE(Actor, _heOffsY, sleInt16, VER(32)),
MKLINE(Actor, _top, sleInt16, VER(8)),
MKLINE(Actor, _bottom, sleInt16, VER(8)),
MKLINE(Actor, _elevation, sleInt16, VER(8)),
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 30dc7789d6..3e8fe6626b 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -61,6 +61,7 @@ struct CostumeData {
uint16 end[16];
uint16 frame[16];
+ /* HE specific */
uint16 heJumpOffsetTable[16];
uint16 heJumpCountTable[16];
uint32 heCondMaskTable[16];
@@ -95,10 +96,6 @@ protected:
Common::Point _pos;
public:
- /** HE specific: This rect is used to clip actor drawing. */
- Common::Rect _clipOverride;
-
- int _offsX, _offsY;
int _top, _bottom;
uint _width;
byte _number;
@@ -137,22 +134,11 @@ public:
CostumeData _cost;
/* HE specific */
- bool _heNoTalkAnimation;
+ int _heOffsX, _heOffsY;
bool _heSkipLimbs;
- bool _heTalking;
uint32 _heCondMask;
uint32 _hePaletteNum;
uint32 _heXmapNum;
- byte _heFlags;
-
- AuxBlock _auxBlock;
-
- struct {
- int16 posX;
- int16 posY;
- int16 color;
- byte sentence[128];
- } _heTalkQueue[16];
protected:
struct ActorWalkData {
@@ -187,7 +173,7 @@ public:
virtual ~Actor() {}
//protected:
- void hideActor();
+ virtual void hideActor();
void showActor();
virtual void initActor(int mode);
@@ -223,10 +209,10 @@ public:
void faceToObject(int obj);
void turnToDirection(int newdir);
virtual void walkActor();
- void drawActorToBackBuf(int x, int y);
void drawActorCostume(bool hitTestMode = false);
+ virtual void prepareDrawActorCostume(BaseCostumeRenderer *bcr);
void animateCostume();
- void setActorCostume(int c);
+ virtual void setActorCostume(int c);
void animateLimb(int limb, int f);
@@ -317,6 +303,27 @@ public:
void classChanged(int cls, bool value);
+ // Used by the save/load system:
+ void saveLoadWithSerializer(Serializer *ser);
+
+protected:
+ bool isInClass(int cls);
+
+ virtual bool isPlayer();
+
+ bool findPathTowards(byte box, byte box2, byte box3, Common::Point &foundPath);
+};
+
+class ActorHE : public Actor {
+public:
+ ActorHE(ScummEngine *scumm, int id) : Actor(scumm, id) {}
+
+ virtual void initActor(int mode);
+
+ virtual void hideActor();
+
+ void drawActorToBackBuf(int x, int y);
+
void setHEFlag(int bit, int set);
void setUserCondition(int slot, int set);
@@ -325,15 +332,26 @@ public:
void setTalkCondition(int slot);
bool isTalkConditionSet(int slot) const;
- // Used by the save/load system:
- void saveLoadWithSerializer(Serializer *ser);
+public:
+ /** This rect is used to clip actor drawing. */
+ Common::Rect _clipOverride;
-protected:
- bool isInClass(int cls);
+ bool _heNoTalkAnimation;
+ bool _heTalking;
+ byte _heFlags;
- virtual bool isPlayer();
+ AuxBlock _auxBlock;
- bool findPathTowards(byte box, byte box2, byte box3, Common::Point &foundPath);
+ struct {
+ int16 posX;
+ int16 posY;
+ int16 color;
+ byte sentence[128];
+ } _heTalkQueue[16];
+
+
+ virtual void prepareDrawActorCostume(BaseCostumeRenderer *bcr);
+ virtual void setActorCostume(int c);
};
class Actor_v3 : public Actor {
@@ -357,6 +375,7 @@ public:
protected:
virtual bool isPlayer();
+ virtual void prepareDrawActorCostume(BaseCostumeRenderer *bcr);
};
class ActorC64 : public Actor_v2 {
diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp
index 8e8fff938d..19c7c3320b 100644
--- a/engines/scumm/akos.cpp
+++ b/engines/scumm/akos.cpp
@@ -1664,28 +1664,28 @@ bool ScummEngine_v6::akos_increaseAnim(Actor *a, int chan, const byte *aksq, con
akos_queCommand(9, a, a->_sound[a->getAnimVar(GB(2))], 0);
continue;
case AKC_C045:
- a->setUserCondition(GB(3), a->getAnimVar(GB(4)));
+ ((ActorHE *)a)->setUserCondition(GB(3), a->getAnimVar(GB(4)));
continue;
case AKC_C046:
- a->setAnimVar(GB(4), a->isUserConditionSet(GB(3)));
+ a->setAnimVar(GB(4), ((ActorHE *)a)->isUserConditionSet(GB(3)));
continue;
case AKC_C047:
- a->setTalkCondition(GB(3));
+ ((ActorHE *)a)->setTalkCondition(GB(3));
continue;
case AKC_C048:
- a->setAnimVar(GB(4), a->isTalkConditionSet(GB(3)));
+ a->setAnimVar(GB(4), ((ActorHE *)a)->isTalkConditionSet(GB(3)));
continue;
case AKC_C0A0:
akos_queCommand(8, a, GB(2), 0);
continue;
case AKC_C0A1:
- if (a->_heTalking != 0) {
+ if (((ActorHE *)a)->_heTalking != 0) {
curpos = GUW(2);
break;
}
continue;
case AKC_C0A2:
- if (a->_heTalking == 0) {
+ if (((ActorHE *)a)->_heTalking == 0) {
curpos = GUW(2);
break;
}
@@ -1763,8 +1763,8 @@ void ScummEngine_v6::akos_processQueue() {
a->_forceClip = param_1;
break;
case 6:
- a->_offsX = param_1;
- a->_offsY = param_2;
+ a->_heOffsX = param_1;
+ a->_heOffsY = param_2;
break;
case 7:
#ifdef ENABLE_HE
@@ -1775,13 +1775,13 @@ void ScummEngine_v6::akos_processQueue() {
case 8:
_actorToPrintStrFor = a->_number;
- a->_talkPosX = a->_heTalkQueue[param_1].posX;
- a->_talkPosY = a->_heTalkQueue[param_1].posY;
- a->_talkColor = a->_heTalkQueue[param_1].color;
+ a->_talkPosX = ((ActorHE *)a)->_heTalkQueue[param_1].posX;
+ a->_talkPosY = ((ActorHE *)a)->_heTalkQueue[param_1].posY;
+ a->_talkColor = ((ActorHE *)a)->_heTalkQueue[param_1].color;
_string[0].loadDefault();
_string[0].color = a->_talkColor;
- actorTalk(a->_heTalkQueue[param_1].sentence);
+ actorTalk(((ActorHE *)a)->_heTalkQueue[param_1].sentence);
break;
case 9:
@@ -1825,8 +1825,8 @@ void ScummEngine_v7::akos_processQueue() {
a->_forceClip = param_1;
break;
case 6:
- a->_offsX = param_1;
- a->_offsY = param_2;
+ a->_heOffsX = param_1;
+ a->_heOffsY = param_2;
break;
case 7:
if (param_1 != 0) {
diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp
index 0fa8b579ca..1e632a034e 100644
--- a/engines/scumm/boxes.cpp
+++ b/engines/scumm/boxes.cpp
@@ -544,8 +544,8 @@ bool ScummEngine::checkXYInBoxBounds(int boxnum, int x, int y) {
// Corner case: If the box is a simple line segment, we consider the
// point to be contained "in" (or rather, lying on) the line if it
// is very close to its projection to the line segment.
- if (box.ul == box.ur && box.lr == box.ll ||
- box.ul == box.ll && box.ur == box.lr) {
+ if ((box.ul == box.ur && box.lr == box.ll) ||
+ (box.ul == box.ll && box.ur == box.lr)) {
Common::Point tmp;
tmp = closestPtOnLine(box.ul, box.lr, p);
@@ -803,8 +803,8 @@ bool Actor::findPathTowards(byte box1nr, byte box2nr, byte box3nr, Common::Point
}
if (box1.ul.y > box2.ur.y || box2.ul.y > box1.ur.y ||
- (box1.ur.y == box2.ul.y || box2.ur.y == box1.ul.y) &&
- box1.ul.y != box1.ur.y && box2.ul.y != box2.ur.y) {
+ ((box1.ur.y == box2.ul.y || box2.ur.y == box1.ul.y) &&
+ box1.ul.y != box1.ur.y && box2.ul.y != box2.ur.y)) {
if (flag & 1)
SWAP(box1.ul.y, box1.ur.y);
if (flag & 2)
@@ -858,8 +858,8 @@ bool Actor::findPathTowards(byte box1nr, byte box2nr, byte box3nr, Common::Point
}
if (box1.ul.x > box2.ur.x || box2.ul.x > box1.ur.x ||
- (box1.ur.x == box2.ul.x || box2.ur.x == box1.ul.x) &&
- box1.ul.x != box1.ur.x && box2.ul.x != box2.ur.x) {
+ ((box1.ur.x == box2.ul.x || box2.ur.x == box1.ul.x) &&
+ box1.ul.x != box1.ur.x && box2.ul.x != box2.ur.x)) {
if (flag & 1)
SWAP(box1.ul.x, box1.ur.x);
if (flag & 2)
@@ -1074,8 +1074,8 @@ bool ScummEngine::areBoxesNeighbours(int box1nr, int box2nr) {
}
if (box.ur.y < box2.ul.y ||
box.ul.y > box2.ur.y ||
- (box.ul.y == box2.ur.y ||
- box.ur.y == box2.ul.y) && box2.ur.y != box2.ul.y && box.ul.y != box.ur.y) {
+ ((box.ul.y == box2.ur.y ||
+ box.ur.y == box2.ul.y) && box2.ur.y != box2.ul.y && box.ul.y != box.ur.y)) {
} else {
return true;
}
@@ -1103,8 +1103,8 @@ bool ScummEngine::areBoxesNeighbours(int box1nr, int box2nr) {
}
if (box.ur.x < box2.ul.x ||
box.ul.x > box2.ur.x ||
- (box.ul.x == box2.ur.x ||
- box.ur.x == box2.ul.x) && box2.ur.x != box2.ul.x && box.ul.x != box.ur.x) {
+ ((box.ul.x == box2.ur.x ||
+ box.ur.x == box2.ul.x) && box2.ur.x != box2.ul.x && box.ul.x != box.ur.x)) {
} else {
return true;
diff --git a/engines/scumm/charset-fontdata.cpp b/engines/scumm/charset-fontdata.cpp
index 6a45d53139..e9a496f6ed 100644
--- a/engines/scumm/charset-fontdata.cpp
+++ b/engines/scumm/charset-fontdata.cpp
@@ -1070,6 +1070,7 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
: CharsetRendererV3(vm) {
_fontHeight = 8;
+ _curId = 0;
switch (language) {
case Common::DE_DEU:
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 5a45fb7da9..609aca996d 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -49,7 +49,7 @@ void ScummEngine::loadCJKFont() {
Common::File fp;
_useCJKMode = false;
_textSurfaceMultiplier = 1;
- _newLineCharacter = 0xfe;
+ _newLineCharacter = 0;
if (_game.version <= 5 && _game.platform == Common::kPlatformFMTowns && _language == Common::JA_JPN) { // FM-TOWNS v3 / v5 Kanji
int numChar = 256 * 32;
@@ -277,7 +277,7 @@ CharsetRenderer::CharsetRenderer(ScummEngine *vm) {
_disableOffsX = false;
_vm = vm;
- _curId = 0;
+ _curId = -1;
}
CharsetRenderer::~CharsetRenderer() {
@@ -289,7 +289,10 @@ CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm)
_shadowColor = 0;
}
-void CharsetRendererCommon::setCurID(byte id) {
+void CharsetRendererCommon::setCurID(int32 id) {
+ if (id == -1)
+ return;
+
assertRange(0, id, _vm->_numCharsets - 1, "charset");
_curId = id;
@@ -308,7 +311,10 @@ void CharsetRendererCommon::setCurID(byte id) {
_numChars = READ_LE_UINT16(_fontPtr + 2);
}
-void CharsetRendererV3::setCurID(byte id) {
+void CharsetRendererV3::setCurID(int32 id) {
+ if (id == -1)
+ return;
+
assertRange(0, id, _vm->_numCharsets - 1, "charset");
_curId = id;
@@ -668,7 +674,8 @@ void CharsetRenderer::translateColor() {
void CharsetRenderer::saveLoadWithSerializer(Serializer *ser) {
static const SaveLoadEntry charsetRendererEntries[] = {
- MKLINE(CharsetRenderer, _curId, sleByte, VER(73)),
+ MKLINE_OLD(CharsetRenderer, _curId, sleByte, VER(73), VER(73)),
+ MKLINE(CharsetRenderer, _curId, sleInt32, VER(74)),
MKLINE(CharsetRenderer, _color, sleByte, VER(73)),
MKEND()
};
@@ -988,7 +995,10 @@ CharsetRendererNut::~CharsetRendererNut() {
}
}
-void CharsetRendererNut::setCurID(byte id) {
+void CharsetRendererNut::setCurID(int32 id) {
+ if (id == -1)
+ return;
+
int numFonts = ((_vm->_game.id == GID_CMI) && (_vm->_game.features & GF_DEMO)) ? 4 : 5;
assert(id < numFonts);
_curId = id;
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index b62dbc6006..dbe02fc8fc 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -67,7 +67,7 @@ public:
protected:
ScummEngine *_vm;
- byte _curId;
+ int32 _curId;
public:
CharsetRenderer(ScummEngine *vm);
@@ -80,7 +80,7 @@ public:
void addLinebreaks(int a, byte *str, int pos, int maxwidth);
void translateColor();
- virtual void setCurID(byte id) = 0;
+ virtual void setCurID(int32 id) = 0;
int getCurID() { return _curId; }
virtual int getFontHeight() = 0;
@@ -113,7 +113,7 @@ protected:
public:
CharsetRendererCommon(ScummEngine *vm);
- void setCurID(byte id);
+ void setCurID(int32 id);
int getFontHeight();
};
@@ -142,7 +142,7 @@ protected:
public:
CharsetRendererNES(ScummEngine *vm) : CharsetRendererCommon(vm) {}
- void setCurID(byte id) {}
+ void setCurID(int32 id) {}
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, const Graphics::Surface &s, int x, int y);
@@ -159,7 +159,7 @@ public:
void printChar(int chr, bool ignoreCharsetMask);
void drawChar(int chr, const Graphics::Surface &s, int x, int y);
- void setCurID(byte id);
+ void setCurID(int32 id);
void setColor(byte color);
int getCharWidth(byte chr);
};
@@ -168,7 +168,7 @@ class CharsetRendererV2 : public CharsetRendererV3 {
public:
CharsetRendererV2(ScummEngine *vm, Common::Language language);
- void setCurID(byte id) {}
+ void setCurID(int32 id) {}
int getCharWidth(byte chr) { return 8; }
};
@@ -184,7 +184,7 @@ public:
void printChar(int chr, bool ignoreCharsetMask);
- void setCurID(byte id);
+ void setCurID(int32 id);
int getFontHeight();
int getCharHeight(byte chr);
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 68d3010199..d3397fe208 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -177,7 +177,7 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
}
struct DetectorDesc {
- FilesystemNode node;
+ Common::FilesystemNode node;
Common::String md5;
const MD5Table *md5Entry; // Entry of the md5 table corresponding to this file, if any.
};
@@ -191,8 +191,8 @@ static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Com
// when performing the matching. The first match is returned, so if you
// search for "resource" and two nodes "RESOURE and "resource" are present,
// the first match is used.
-static bool searchFSNode(const FSList &fslist, const Common::String &name, FilesystemNode &result) {
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+static bool searchFSNode(const Common::FSList &fslist, const Common::String &name, Common::FilesystemNode &result) {
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (!scumm_stricmp(file->getName().c_str(), name.c_str())) {
result = *file;
return true;
@@ -202,7 +202,7 @@ static bool searchFSNode(const FSList &fslist, const Common::String &name, Files
}
// The following function tries to detect the language for COMI and DIG
-static Common::Language detectLanguage(const FSList &fslist, byte id) {
+static Common::Language detectLanguage(const Common::FSList &fslist, byte id) {
assert(id == GID_CMI || id == GID_DIG);
// Check for LANGUAGE.BND (Dig) resp. LANGUAGE.TAB (CMI).
@@ -212,14 +212,14 @@ static Common::Language detectLanguage(const FSList &fslist, byte id) {
// switch to MD5 based detection).
const char *filename = (id == GID_CMI) ? "LANGUAGE.TAB" : "LANGUAGE.BND";
Common::File tmp;
- FilesystemNode langFile;
+ Common::FilesystemNode langFile;
if (!searchFSNode(fslist, filename, langFile) || !tmp.open(langFile)) {
// try loading in RESOURCE sub dir...
- FilesystemNode resDir;
- FSList tmpList;
+ Common::FilesystemNode resDir;
+ Common::FSList tmpList;
if (searchFSNode(fslist, "RESOURCE", resDir)
&& resDir.isDirectory()
- && resDir.getChildren(tmpList, FilesystemNode::kListFilesOnly)
+ && resDir.getChildren(tmpList, Common::FilesystemNode::kListFilesOnly)
&& searchFSNode(tmpList, filename, langFile)) {
tmp.open(langFile);
}
@@ -270,7 +270,7 @@ static Common::Language detectLanguage(const FSList &fslist, byte id) {
}
-static void computeGameSettingsFromMD5(const FSList &fslist, const GameFilenamePattern *gfp, const MD5Table *md5Entry, DetectorResult &dr) {
+static void computeGameSettingsFromMD5(const Common::FSList &fslist, const GameFilenamePattern *gfp, const MD5Table *md5Entry, DetectorResult &dr) {
dr.language = md5Entry->language;
dr.extra = md5Entry->extra;
@@ -315,12 +315,12 @@ static void computeGameSettingsFromMD5(const FSList &fslist, const GameFilenameP
}
}
-static void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) {
+static void detectGames(const Common::FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) {
DescMap fileMD5Map;
DetectorResult dr;
char md5str[32+1];
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (!file->isDirectory()) {
DetectorDesc d;
d.node = *file;
@@ -674,15 +674,30 @@ public:
virtual const char *getName() const;
virtual const char *getCopyright() const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const FSList &fslist) const;
-
+ virtual GameList detectGames(const Common::FSList &fslist) const;
+
virtual PluginError createInstance(OSystem *syst, Engine **engine) const;
virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+ virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
+bool ScummMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSupportsMetaInfos) ||
+ (f == kSupportsThumbnails) ||
+ (f == kSupportsSaveDate) ||
+ (f == kSupportsSavePlayTime);
+}
+
GameList ScummMetaEngine::getSupportedGames() const {
return GameList(gameDescriptions);
}
@@ -691,8 +706,7 @@ GameDescriptor ScummMetaEngine::findGame(const char *gameid) const {
return Common::AdvancedDetector::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable);
}
-
-GameList ScummMetaEngine::detectGames(const FSList &fslist) const {
+GameList ScummMetaEngine::detectGames(const Common::FSList &fslist) const {
GameList detectedGames;
Common::List<DetectorResult> results;
@@ -769,9 +783,9 @@ PluginError ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
}
// Fetch the list of files in the current directory
- FSList fslist;
- FilesystemNode dir(ConfMan.get("path"));
- if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) {
+ Common::FSList fslist;
+ Common::FilesystemNode dir(ConfMan.get("path"));
+ if (!dir.getChildren(fslist, Common::FilesystemNode::kListFilesOnly)) {
return kInvalidPathError;
}
@@ -820,9 +834,10 @@ PluginError ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
// unknown MD5, or with a medium debug level in case of a known MD5 (for
// debugging purposes).
if (!findInMD5Table(res.md5.c_str())) {
- printf("Your game version appears to be unknown. Please, report the following\n");
- printf("data to the ScummVM team along with name of the game you tried to add\n");
- printf("and its version/language/etc.:\n");
+ printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n");
+ printf("version (in particular, not a fan-made translation), please, report the\n");
+ printf("following data to the ScummVM team along with name of the game you tried\n");
+ printf("to add and its version/language/etc.:\n");
printf(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n",
res.game.gameid,
@@ -966,6 +981,53 @@ SaveStateList ScummMetaEngine::listSaves(const char *target) const {
return saveList;
}
+void ScummMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String filename = ScummEngine::makeSavegameName(target, slot, false);
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
+SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = ScummEngine::makeSavegameName(target, slot, false);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
+
+ if (!in)
+ return SaveStateDescriptor();
+
+ Common::String saveDesc;
+ Scumm::getSavegameName(in, saveDesc, 0); // FIXME: heversion?!?
+ delete in;
+
+ // TODO: Cleanup
+ Graphics::Surface *thumbnail = ScummEngine::loadThumbnailFromSlot(target, slot);
+
+ SaveStateDescriptor desc(slot, saveDesc, filename);
+ desc.setDeletableFlag(true);
+ desc.setThumbnail(thumbnail);
+
+ InfoStuff infos;
+ memset(&infos, 0, sizeof(infos));
+ if (ScummEngine::loadInfosFromSlot(target, slot, &infos)) {
+ int day = (infos.date >> 24) & 0xFF;
+ int month = (infos.date >> 16) & 0xFF;
+ int year = infos.date & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (infos.time >> 8) & 0xFF;
+ int minutes = infos.time & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ minutes = infos.playtime / 60;
+ hour = minutes / 60;
+ minutes %= 60;
+
+ desc.setPlayTime(hour, minutes);
+ }
+
+ return desc;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(SCUMM)
REGISTER_PLUGIN_DYNAMIC(SCUMM, PLUGIN_TYPE_ENGINE, ScummMetaEngine);
#else
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 324cc91e78..8d70afecf2 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -472,12 +472,14 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "fbear", "fbdemo", kGenHEPC, UNK_LANG, UNK, 0 },
{ "fbear", "Fatty Bear Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "fbear", "Fatty Bear", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },
+ { "fbear", "jfbear", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 },
{ "puttmoon", "puttmoon", kGenHEPC, UNK_LANG, UNK, 0 },
{ "puttmoon", "moondemo", kGenHEPC, UNK_LANG, UNK, 0 },
{ "puttmoon", "Putt-Putt Moon Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "puttmoon", "Putt-Putt Moon", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },
+ { "puttputt", "jputtputt", kGenHEPC, Common::JA_JPN, Common::kPlatform3DO, 0 },
{ "puttputt", "puttputt", kGenHEPC, UNK_LANG, UNK, 0 },
{ "puttputt", "puttdemo", kGenHEPC, UNK_LANG, UNK, 0 },
{ "puttputt", "Putt-Putt's Demo", kGenHEMacNoParens, UNK_LANG, Common::kPlatformMacintosh, 0 },
@@ -711,6 +713,7 @@ static const GameFilenamePattern gameFilenamesTable[] = {
{ "puttrace", "racedemo", kGenHEPC, UNK_LANG, UNK, 0 },
{ "puttrace", "RaceDemo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 },
{ "puttrace", "Rennen", kGenHEPC, Common::DE_DEU, UNK, 0 },
+ { "puttrace", "PouceCourse", kGenHEPC, Common::FR_FRA, UNK, 0 },
{ "puttrace", "Putt500", kGenHEPC, Common::NL_NLD, UNK, 0 },
{ "puttrace", "Putt500", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 },
{ "puttrace", "Putt500 demo", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 },
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index e4e2b2b620..799203abe7 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -244,9 +244,6 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel,
_list->setEditable(saveMode);
_list->setNumberingMode(saveMode ? GUI::kListNumberingOne : GUI::kListNumberingZero);
- _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
- _container->setHints(GUI::THEME_HINT_USE_SHADOW);
-
_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
_date = new StaticTextWidget(this, 0, 0, 10, 10, "No date saved", kTextAlignCenter);
@@ -257,6 +254,9 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel,
new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
_chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
+
+ _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
+ _container->setHints(GUI::THEME_HINT_USE_SHADOW);
}
SaveLoadChooser::~SaveLoadChooser() {
@@ -364,62 +364,50 @@ void SaveLoadChooser::reflowLayout() {
void SaveLoadChooser::updateInfos(bool redraw) {
int selItem = _list->getSelected();
- Graphics::Surface *thumb;
- thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
+ Graphics::Surface *thumb = 0;
+ if (selItem >= 0 && !_list->getSelectedString().empty())
+ thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
if (thumb) {
_gfxWidget->setGfx(thumb);
_gfxWidget->useAlpha(256);
thumb->free();
+ delete thumb;
} else {
_gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
}
- delete thumb;
- if (redraw)
- _gfxWidget->draw();
-
InfoStuff infos;
memset(&infos, 0, sizeof(InfoStuff));
- char buffer[32];
- if (_vm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
+ if (selItem >= 0 && !_list->getSelectedString().empty()
+ && _vm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
+ char buffer[32];
snprintf(buffer, 32, "Date: %.2d.%.2d.%.4d",
(infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF,
infos.date & 0xFFFF);
_date->setLabel(buffer);
- if (redraw)
- _date->draw();
snprintf(buffer, 32, "Time: %.2d:%.2d",
(infos.time >> 8) & 0xFF, infos.time & 0xFF);
_time->setLabel(buffer);
- if (redraw)
- _time->draw();
int minutes = infos.playtime / 60;
int hours = minutes / 60;
minutes %= 60;
- snprintf(buffer, 32, "Playtime: %.2d:%.2d",
- hours & 0xFF, minutes & 0xFF);
+ snprintf(buffer, 32, "Playtime: %.2d:%.2d", hours, minutes);
_playtime->setLabel(buffer);
- if (redraw)
- _playtime->draw();
} else {
- snprintf(buffer, 32, "No date saved");
- _date->setLabel(buffer);
- if (redraw)
- _date->draw();
-
- snprintf(buffer, 32, "No time saved");
- _time->setLabel(buffer);
- if (redraw)
- _time->draw();
+ _date->setLabel("No date saved");
+ _time->setLabel("No time saved");
+ _playtime->setLabel("No playtime saved");
+ }
- snprintf(buffer, 32, "No playtime saved");
- _playtime->setLabel(buffer);
- if (redraw)
- _playtime->draw();
+ if (redraw) {
+ _gfxWidget->draw();
+ _date->draw();
+ _time->draw();
+ _playtime->draw();
}
}
@@ -442,7 +430,7 @@ Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode) {
return descriptions;
}
-MainMenuDialog::MainMenuDialog(ScummEngine *scumm)
+ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
: ScummDialog("scummmain"), _vm(scumm) {
new GUI::ButtonWidget(this, "scummmain_resume", "Resume", kPlayCmd, 'P');
@@ -470,7 +458,7 @@ MainMenuDialog::MainMenuDialog(ScummEngine *scumm)
_loadDialog = new SaveLoadChooser("Load game:", "Load", false, scumm);
}
-MainMenuDialog::~MainMenuDialog() {
+ScummMenuDialog::~ScummMenuDialog() {
delete _aboutDialog;
delete _optionsDialog;
#ifndef DISABLE_HELP
@@ -480,7 +468,7 @@ MainMenuDialog::~MainMenuDialog() {
delete _loadDialog;
}
-void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kSaveCmd:
save();
@@ -503,7 +491,7 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
break;
#endif
case kQuitCmd:
- _vm->_quit = true;
+ _vm->quitGame();
close();
break;
default:
@@ -511,7 +499,7 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
}
}
-void MainMenuDialog::save() {
+void ScummMenuDialog::save() {
int idx;
_saveDialog->setList(generateSavegameList(_vm, true));
idx = _saveDialog->runModal();
@@ -530,7 +518,7 @@ void MainMenuDialog::save() {
}
}
-void MainMenuDialog::load() {
+void ScummMenuDialog::load() {
int idx;
_loadDialog->setList(generateSavegameList(_vm, false));
idx = _loadDialog->runModal();
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 0d04d8faea..3837787a3b 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -82,10 +82,10 @@ public:
virtual void reflowLayout();
};
-class MainMenuDialog : public ScummDialog {
+class ScummMenuDialog : public ScummDialog {
public:
- MainMenuDialog(ScummEngine *scumm);
- ~MainMenuDialog();
+ ScummMenuDialog(ScummEngine *scumm);
+ ~ScummMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
protected:
diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp
index bf13308a0c..f258ddd420 100644
--- a/engines/scumm/file.cpp
+++ b/engines/scumm/file.cpp
@@ -42,9 +42,9 @@ void ScummFile::setEnc(byte value) {
_encbyte = value;
}
-void ScummFile::setSubfileRange(uint32 start, uint32 len) {
+void ScummFile::setSubfileRange(int32 start, int32 len) {
// TODO: Add sanity checks
- const uint32 fileSize = File::size();
+ const int32 fileSize = File::size();
assert(start <= fileSize);
assert(start + len <= fileSize);
_subFileStart = start;
@@ -125,19 +125,19 @@ bool ScummFile::openSubFile(const Common::String &filename) {
}
-bool ScummFile::eof() {
- return _subFileLen ? (pos() >= _subFileLen) : File::eof();
+bool ScummFile::eos() {
+ return _subFileLen ? (pos() >= _subFileLen) : File::eos(); // FIXME
}
-uint32 ScummFile::pos() {
+int32 ScummFile::pos() {
return File::pos() - _subFileStart;
}
-uint32 ScummFile::size() {
+int32 ScummFile::size() {
return _subFileLen ? _subFileLen : File::size();
}
-void ScummFile::seek(int32 offs, int whence) {
+bool ScummFile::seek(int32 offs, int whence) {
if (_subFileLen) {
// Constrain the seek to the subfile
switch (whence) {
@@ -154,7 +154,7 @@ void ScummFile::seek(int32 offs, int whence) {
assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen));
whence = SEEK_SET;
}
- File::seek(offs, whence);
+ return File::seek(offs, whence);
}
uint32 ScummFile::read(void *dataPtr, uint32 dataSize) {
@@ -162,12 +162,12 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) {
if (_subFileLen) {
// Limit the amount we read by the subfile boundaries.
- const uint32 curPos = pos();
+ const int32 curPos = pos();
assert(_subFileLen >= curPos);
- uint32 newPos = curPos + dataSize;
+ int32 newPos = curPos + dataSize;
if (newPos > _subFileLen) {
dataSize = _subFileLen - curPos;
- _ioFailed = true;
+ _myIoFailed = true;
}
}
diff --git a/engines/scumm/file.h b/engines/scumm/file.h
index a2695cac59..336f3cde12 100644
--- a/engines/scumm/file.h
+++ b/engines/scumm/file.h
@@ -39,32 +39,37 @@ public:
virtual bool open(const Common::String &filename) = 0;
virtual bool openSubFile(const Common::String &filename) = 0;
- virtual bool eof() = 0;
- virtual uint32 pos() = 0;
- virtual uint32 size() = 0;
- virtual void seek(int32 offs, int whence = SEEK_SET) = 0;
+ virtual bool eos() = 0;
+ virtual int32 pos() = 0;
+ virtual int32 size() = 0;
+ virtual bool seek(int32 offs, int whence = SEEK_SET) = 0;
virtual uint32 read(void *dataPtr, uint32 dataSize) = 0;
};
class ScummFile : public BaseScummFile {
private:
byte _encbyte;
- uint32 _subFileStart;
- uint32 _subFileLen;
+ int32 _subFileStart;
+ int32 _subFileLen;
+ bool _myIoFailed;
+
+ void setSubfileRange(int32 start, int32 len);
+ void resetSubfile();
+
public:
ScummFile();
void setEnc(byte value);
- void setSubfileRange(uint32 start, uint32 len);
- void resetSubfile();
-
bool open(const Common::String &filename);
bool openSubFile(const Common::String &filename);
- bool eof();
- uint32 pos();
- uint32 size();
- void seek(int32 offs, int whence = SEEK_SET);
+ bool ioFailed() const { return _myIoFailed || BaseScummFile::ioFailed(); }
+ void clearIOFailed() { _myIoFailed = false; BaseScummFile::clearIOFailed(); }
+
+ bool eos();
+ int32 pos();
+ int32 size();
+ bool seek(int32 offs, int whence = SEEK_SET);
uint32 read(void *dataPtr, uint32 dataSize);
};
@@ -106,10 +111,10 @@ public:
bool openSubFile(const Common::String &filename);
void close();
- bool eof() { return _stream->eos(); }
- uint32 pos() { return _stream->pos(); }
- uint32 size() { return _stream->size(); }
- void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); }
+ bool eos() { return _stream->eos(); }
+ int32 pos() { return _stream->pos(); }
+ int32 size() { return _stream->size(); }
+ bool seek(int32 offs, int whence = SEEK_SET) { return _stream->seek(offs, whence); }
uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); }
};
diff --git a/engines/scumm/file_nes.cpp b/engines/scumm/file_nes.cpp
index 8325436f87..0ddbd0b3ee 100644
--- a/engines/scumm/file_nes.cpp
+++ b/engines/scumm/file_nes.cpp
@@ -1124,8 +1124,7 @@ bool ScummNESFile::generateResource(int res) {
write_byte(&out, 0xD1);
write_byte(&out, 0xF5);
- if (_stream)
- delete _stream;
+ delete _stream;
_stream = new Common::MemoryReadStream(_buf, bufsize);
@@ -1221,8 +1220,7 @@ bool ScummNESFile::generateIndex() {
for (i = 0; i < (int)sizeof(lfl_index); i++)
write_byte(&out, ((byte *)&lfl_index)[i]);
- if (_stream)
- delete _stream;
+ delete _stream;
_stream = new Common::MemoryReadStream(_buf, bufsize);
diff --git a/engines/scumm/file_nes.h b/engines/scumm/file_nes.h
index 4d2d6de275..f1a07f8085 100644
--- a/engines/scumm/file_nes.h
+++ b/engines/scumm/file_nes.h
@@ -68,10 +68,10 @@ public:
bool openSubFile(const Common::String &filename);
void close();
- bool eof() { return _stream->eos(); }
- uint32 pos() { return _stream->pos(); }
- uint32 size() { return _stream->size(); }
- void seek(int32 offs, int whence = SEEK_SET) { _stream->seek(offs, whence); }
+ bool eos() { return _stream->eos(); }
+ int32 pos() { return _stream->pos(); }
+ int32 size() { return _stream->size(); }
+ bool seek(int32 offs, int whence = SEEK_SET) { return _stream->seek(offs, whence); }
uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); }
};
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 6c8d24d25a..4e8c22479d 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -22,7 +22,6 @@
*
*/
-
#include "common/system.h"
#include "scumm/scumm.h"
#include "scumm/actor.h"
@@ -46,7 +45,7 @@ namespace Scumm {
static void blit(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h);
static void fill(byte *dst, int dstPitch, byte color, int w, int h);
-#ifndef ARM_USE_GFX_ASM
+#ifndef USE_ARM_GFX_ASM
static void copy8Col(byte *dst, int dstPitch, const byte *src, int height);
#endif
static void clear8Col(byte *dst, int dstPitch, int height);
@@ -577,15 +576,12 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
const byte *src = vs->getPixels(x, top);
int m = _textSurfaceMultiplier;
- byte *dst;
int vsPitch;
int pitch = vs->pitch;
if (_useCJKMode && _textSurfaceMultiplier == 2) {
- dst = _fmtownsBuf;
-
- scale2x(dst, _screenWidth * m, src, vs->pitch, width, height);
- src = dst;
+ scale2x(_fmtownsBuf, _screenWidth * m, src, vs->pitch, width, height);
+ src = _fmtownsBuf;
vsPitch = _screenWidth * m - width * m;
@@ -593,7 +589,6 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
vsPitch = vs->pitch - width;
}
- dst = _compositeBuf;
if (_game.version < 7) {
// For The Dig, FT and COMI, we just blit everything to the screen at once.
@@ -612,32 +607,37 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
assert(0 == (width & 3));
// Compose the text over the game graphics
-
- // TODO: Optimize this code. There are several things that come immediately to mind:
- // (1) Loop unrolling: We could read 4 or even 8 pixels at once, since everything is
- // a multiple of 8 here.
- // (2) More ASM versions (in particular, the ARM code for the NDS could be used on
- // all ARM systems, couldn't it?)
- // (3) Better encoding of the text surface data. This is the one with the biggest
- // potential.
- // (a) Keep an "isEmpty" marker for each pixel row in the _textSurface. The idea
- // is that most rows won't contain any text data, so we can just use memcpy.
- // (b) RLE encode the _textSurface row-wise. This is an improved variant of (a),
- // but also more complicated to implement, and incurs a bigger overhead when
- // writing to the text surface.
-#ifdef ARM_USE_GFX_ASM
- asmDrawStripToScreen(height, width, text, src, dst, vs->pitch, width, _textSurface.pitch);
+#ifdef USE_ARM_GFX_ASM
+ asmDrawStripToScreen(height, width, text, src, _compositeBuf, vs->pitch, width, _textSurface.pitch);
#else
- for (int h = 0; h < height * m; ++h) {
- for (int w = 0; w < width * m; ++w) {
- byte tmp = *text++;
- if (tmp == CHARSET_MASK_TRANSPARENCY)
- tmp = *src;
- *dst++ = tmp;
- src++;
+ // We blit four pixels at a time, for improved performance.
+ const uint32 *src32 = (const uint32 *)src;
+ const uint32 *text32 = (const uint32 *)text;
+ uint32 *dst32 = (uint32 *)_compositeBuf;
+
+ vsPitch >>= 2;
+ const int textPitch = (_textSurface.pitch - width * m) >> 2;
+ for (int h = height * m; h > 0; --h) {
+ for (int w = width*m; w > 0; w-=4) {
+ uint32 temp = *text32++;
+
+ // Generate a byte mask for those text pixels (bytes) with
+ // value CHARSET_MASK_TRANSPARENCY. In the end, each byte
+ // in mask will be either equal to 0x00 or 0xFF.
+ // Doing it this way avoids branches and bytewise operations,
+ // at the cost of readability ;).
+ uint32 mask = temp ^ CHARSET_MASK_TRANSPARENCY_32;
+ mask = (((mask & 0x7f7f7f7f) + 0x7f7f7f7f) | mask) & 0x80808080;
+ mask = ((mask >> 7) + 0x7f7f7f7f) ^ 0x80808080;
+
+ // The following line is equivalent to this code:
+ // *dst32++ = (*src32++ & mask) | (temp & ~mask);
+ // However, some compilers can generate somewhat better
+ // machine code for this equivalent statement:
+ *dst32++ = ((temp ^ *src32++) & mask) ^ temp;
}
- src += vsPitch;
- text += _textSurface.pitch - width * m;
+ src32 += vsPitch;
+ text32 += textPitch;
}
#endif
src = _compositeBuf;
@@ -669,7 +669,7 @@ void ScummEngine::drawStripToScreen(VirtScreen *vs, int x, int width, int top, i
x += 16;
while (x + width >= _screenWidth)
width -= 16;
- if (width < 0)
+ if (width <= 0)
return;
}
@@ -1078,7 +1078,7 @@ static void fill(byte *dst, int dstPitch, byte color, int w, int h) {
}
}
-#ifdef ARM_USE_GFX_ASM
+#ifdef USE_ARM_GFX_ASM
#define copy8Col(A,B,C,D) asmCopy8Col(A,B,C,D)
@@ -1098,7 +1098,7 @@ static void copy8Col(byte *dst, int dstPitch, const byte *src, int height) {
} while (--height);
}
-#endif /* ARM_USE_GFX_ASM */
+#endif /* USE_ARM_GFX_ASM */
static void clear8Col(byte *dst, int dstPitch, int height) {
do {
diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h
index e03fdd1c53..e4c1054450 100644
--- a/engines/scumm/gfx.h
+++ b/engines/scumm/gfx.h
@@ -174,7 +174,8 @@ struct ColorCycle {
struct StripTable;
-#define CHARSET_MASK_TRANSPARENCY 253
+#define CHARSET_MASK_TRANSPARENCY 0xFD
+#define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD
class Gdi {
protected:
diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s
index 83aaa78927..f3a1f20303 100644
--- a/engines/scumm/gfxARM.s
+++ b/engines/scumm/gfxARM.s
@@ -24,7 +24,7 @@
.global asmDrawStripToScreen
.global asmCopy8Col
-
+
@ ARM implementation of asmDrawStripToScreen.
@
@ C prototype would be:
@@ -47,7 +47,7 @@ asmDrawStripToScreen:
@ r2 = text
@ r3 = src
MOV r12,r13
- STMFD r13!,{r4-r7,r9-r11,R14}
+ STMFD r13!,{r4-r11,R14}
LDMIA r12,{r4,r5,r6,r7}
@ r4 = dst
@ r5 = vsPitch
@@ -69,57 +69,46 @@ asmDrawStripToScreen:
MOV r10,#253
ORR r10,r10,r10,LSL #8
ORR r10,r10,r10,LSL #16 @ r10 = mask
-yLoop:
- MOV r14,r1 @ r14 = width
+ MOV r8,#0x7F
+ ORR r8, r8, r8, LSL #8
+ ORR r8, r8, r8, LSL #16 @ r8 = 7f7f7f7f
+ STR r1,[r13,#-4]! @ Stack width
+ B xLoop
+
+notEntirelyTransparent:
+ AND r14,r9, r8 @ r14 = mask & 7f7f7f7f
+ ADD r14,r14,r8 @ r14 = (mask & 7f7f7f7f)+7f7f7f7f
+ ORR r14,r14,r9 @ r14 |= mask
+ BIC r14,r14,r8 @ r14 &= 80808080
+ ADD r14,r8, r14,LSR #7 @ r14 = (rx>>7) + 7f7f7f7f
+ EOR r14,r14,r8 @ r14 ^= 7f7f7f7f
+ @ So bytes of r14 are 00 where source was matching value,FF otherwise
+ BIC r11,r11,r14
+ AND r12,r12,r14
+ ORR r12,r11,r12
+ STR r12,[r4],#4
+ SUBS r1,r1,#4
+ BLE endXLoop
xLoop:
- LDR r12,[r2],#4 @ r12 = [text]
- LDR r11,[r3],#4 @ r11 = [src]
- CMP r12,r10
- BNE singleByteCompare
- SUBS r14,r14,#4
+ LDR r12,[r2],#4 @ r12 = temp = [text]
+ LDR r11,[r3],#4 @ r11 = [src]
+ @ Stall
+ EORS r9, r12,r10 @ r9 = mask = temp ^ TRANSPARENCY
+ BNE notEntirelyTransparent
+ SUBS r1, r1, #4
STR r11,[r4], #4 @ r4 = [dst]
BGT xLoop
-
+endXLoop:
ADD r2,r2,r7 @ text += textSurfacePitch
ADD r3,r3,r5 @ src += vsPitch
ADD r4,r4,r6 @ dst += vmScreenWidth
SUBS r0,r0,#1
- BGT yLoop
- LDMFD r13!,{r4-r7,r9-r11,PC}
-
-singleByteCompare:
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- MOV r9,r12,LSR #24 @ r9 = 1st byte of [text]
- CMP r9,r10,LSR #24 @ if (r9 == mask)
- MOVEQ r9,r11,LSR #24 @ r9 = 1st byte of [src]
- ORR r12,r9,r12,LSL #8 @ r12 = combine r9 and r12
-
- STR r12,[r4],#4
- SUBS r14,r14,#4
+ LDRGT r1,[r13] @ r14 = width
BGT xLoop
-
- ADD r2,r2,r7 @ text += textSurfacePitch
- ADD r3,r3,r5 @ src += vsPitch
- ADD r4,r4,r6 @ dst += vmScreenWidth
- SUBS r0,r0,#1
- BGT yLoop
+ ADD r13,r13,#4
end:
- LDMFD r13!,{r4-r7,r9-r11,PC}
-
+ LDMFD r13!,{r4-r11,PC}
+
@ ARM implementation of asmCopy8Col
@
@ C prototype would be:
@@ -156,4 +145,4 @@ roll2:
STR r14,[r0],r1
BNE yLoop2
- LDMFD r13!,{PC}
+ LDMFD r13!,{PC}
diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp
index e611c85e9d..685bd00065 100644
--- a/engines/scumm/he/cup_player_he.cpp
+++ b/engines/scumm/he/cup_player_he.cpp
@@ -99,7 +99,7 @@ void CUP_Player::play() {
debug(1, "rate %d width %d height %d", _playbackRate, _width, _height);
int ticks = _system->getMillis();
- while (_dataSize != 0 && !_vm->_quit) {
+ while (_dataSize != 0 && !_vm->quit()) {
while (parseNextBlockTag(_fileStream)) {
if (_fileStream.ioFailed()) {
return;
@@ -190,7 +190,7 @@ void CUP_Player::waitForSfxChannel(int channel) {
CUP_SfxChannel *sfxChannel = &_sfxChannels[channel];
debug(1, "waitForSfxChannel %d", channel);
if ((sfxChannel->flags & kSfxFlagLoop) == 0) {
- while (_mixer->isSoundHandleActive(sfxChannel->handle) && !_vm->_quit) {
+ while (_mixer->isSoundHandleActive(sfxChannel->handle) && !_vm->quit()) {
_vm->parseEvents();
_system->delayMillis(10);
}
@@ -496,7 +496,7 @@ void CUP_Player::handleTOIL(Common::SeekableReadStream &dataStream, uint32 dataS
for (int i = 0; i < kSfxChannels; ++i) {
waitForSfxChannel(i);
}
- _vm->_quit = true;
+ _vm->quitGame();
break;
case 7: {
int channelSync = dataStream.readUint32LE();
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index fff8502134..8fd9122503 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -39,6 +39,7 @@ class WriteStream;
namespace Scumm {
+class ActorHE;
class ResExtractor;
#ifdef ENABLE_HE
class LogicHE;
@@ -243,7 +244,7 @@ public:
AuxEntry _auxEntries[16];
uint16 _auxEntriesNum;
- void queueAuxBlock(Actor *a);
+ void queueAuxBlock(ActorHE *a);
void queueAuxEntry(int actorNum, int subIndex);
void remapHEPalette(const uint8 *src, uint8 *dst);
@@ -320,6 +321,8 @@ protected:
virtual bool handleNextCharsetCode(Actor *a, int *c);
virtual int convertMessageToString(const byte *msg, byte *dst, int dstSize);
+ void debugInput(byte *string);
+
/* HE version 72 script opcodes */
void o72_pushDWord();
void o72_getScriptString();
@@ -602,9 +605,12 @@ protected:
const OpcodeEntryV100he *_opcodesV100he;
+ byte _debugInputBuffer[256];
public:
ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {}
+ virtual void resetScumm();
+
protected:
virtual void setupOpcodes();
virtual void executeOpcode(byte i);
@@ -643,6 +649,7 @@ protected:
void o100_videoOps();
void o100_wait();
void o100_writeFile();
+ void o100_debugInput();
void o100_isResourceLoaded();
void o100_getResourceSize();
void o100_getSpriteGroupInfo();
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index f72701c229..f1a202e22c 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -23,12 +23,11 @@
*
*/
-
-
#include "common/system.h"
#include "scumm/actor.h"
#include "scumm/charset.h"
+#include "scumm/dialogs.h"
#include "scumm/he/animation_he.h"
#include "scumm/he/intern_he.h"
#include "scumm/object.h"
@@ -256,7 +255,7 @@ void ScummEngine_v100he::setupOpcodes() {
OPCODE(o90_cond),
OPCODE(o90_cos),
/* A8 */
- OPCODE(o6_invalid),
+ OPCODE(o100_debugInput),
OPCODE(o80_getFileSize),
OPCODE(o6_getActorFromXY),
OPCODE(o72_findAllObjects),
@@ -380,7 +379,7 @@ const char *ScummEngine_v100he::getOpcodeDesc(byte i) {
}
void ScummEngine_v100he::o100_actorOps() {
- Actor *a;
+ ActorHE *a;
int i, j, k;
int args[32];
byte string[256];
@@ -391,7 +390,7 @@ void ScummEngine_v100he::o100_actorOps() {
return;
}
- a = derefActorSafe(_curActor, "o100_actorOps");
+ a = (ActorHE *)derefActorSafe(_curActor, "o100_actorOps");
if (!a)
return;
@@ -1116,6 +1115,10 @@ void ScummEngine_v100he::o100_resourceRoutines() {
_heResId = pop();
break;
case 128:
+ // TODO: Clear Heap
+ break;
+ case 129:
+ // Dummy case
break;
case 132:
if (_heResType == rtScript && _heResId >= _numGlobalScripts)
@@ -2136,31 +2139,30 @@ void ScummEngine_v100he::o100_systemOps() {
byte string[1024];
byte subOp = fetchScriptByte();
- subOp -= 61;
switch (subOp) {
- case 0:
+ case 61:
restart();
break;
- case 67:
+ case 128:
clearDrawObjectQueue();
break;
- case 71:
+ case 132:
// Confirm shutdown
- shutDown();
+ quitGame();
break;
- case 72:
- shutDown();
+ case 133:
+ quitGame();
break;
- case 73:
+ case 134:
copyScriptString(string, sizeof(string));
debug(0, "Start game (%s)", string);
break;
- case 74:
+ case 135:
copyScriptString(string, sizeof(string));
debug(0, "Start executable (%s)", string);
break;
- case 75:
+ case 136:
restoreBackgroundHE(Common::Rect(_screenWidth, _screenHeight));
updatePalette();
break;
@@ -2342,6 +2344,30 @@ void ScummEngine_v100he::o100_writeFile() {
}
}
+void ScummEngine_v100he::o100_debugInput() {
+ byte subOp = fetchScriptByte();
+
+ switch (subOp) {
+ case 0:
+ copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer));
+ break;
+ case 26:
+ pop();
+ break;
+ case 27:
+ copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer));
+ break;
+ case 80:
+ copyScriptString(_debugInputBuffer, sizeof(_debugInputBuffer));
+ break;
+ case 92:
+ debugInput(_debugInputBuffer);
+ break;
+ default:
+ error("o100_debugInput: default case %d", subOp);
+ }
+}
+
void ScummEngine_v100he::o100_isResourceLoaded() {
// Reports percentage of resource loaded by queue
int type;
@@ -2493,65 +2519,64 @@ void ScummEngine_v100he::o100_getWizData() {
int32 x, y;
byte subOp = fetchScriptByte();
- subOp -= 20;
switch (subOp) {
- case 0:
+ case 20:
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->getWizPixelColor(resId, state, x, y, 0));
break;
- case 6:
+ case 26:
resId = pop();
push(_wiz->getWizImageStates(resId));
break;
- case 13:
+ case 33:
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0));
break;
- case 19:
+ case 39:
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(h);
break;
- case 34:
+ case 54:
type = pop();
state = pop();
resId = pop();
push(_wiz->getWizImageData(resId, state, type));
break;
- case 64:
+ case 84:
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(w);
break;
- case 65:
+ case 85:
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(x);
break;
- case 66:
+ case 86:
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(y);
break;
- case 111:
+ case 131:
pop();
copyScriptString(filename, sizeof(filename));
pop();
push(0);
debug(0, "o100_getWizData() case 111 unhandled");
break;
- case 112:
+ case 132:
h = pop();
w = pop();
y = pop();
@@ -2896,30 +2921,29 @@ void ScummEngine_v100he::o100_getSpriteInfo() {
void ScummEngine_v100he::o100_getVideoData() {
// Uses Bink video
byte subOp = fetchScriptByte();
- subOp -= 26;
switch (subOp) {
- case 0:
+ case 26:
pop();
push(_moviePlay->getFrameCount());
break;
- case 13:
+ case 39:
pop();
push(_moviePlay->getHeight());
break;
- case 14:
+ case 40:
pop();
push(_moviePlay->getImageNum());
break;
- case 28:
+ case 54:
debug(0, "o100_getVideoData: subOp 28 stub (%d, %d)", pop(), pop());
push(0);
break;
- case 47:
+ case 73:
pop();
push(_moviePlay->getCurFrame());
break;
- case 58:
+ case 84:
pop();
push(_moviePlay->getWidth());
break;
diff --git a/engines/scumm/he/script_v60he.cpp b/engines/scumm/he/script_v60he.cpp
index 9429f8d086..7f36d53791 100644
--- a/engines/scumm/he/script_v60he.cpp
+++ b/engines/scumm/he/script_v60he.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "common/savefile.h"
#include "scumm/actor.h"
@@ -623,7 +622,7 @@ void ScummEngine_v60he::swapObjects(int object1, int object2) {
}
void ScummEngine_v60he::o60_actorOps() {
- Actor *a;
+ ActorHE *a;
int i, j, k;
int args[8];
@@ -633,7 +632,7 @@ void ScummEngine_v60he::o60_actorOps() {
return;
}
- a = derefActorSafe(_curActor, "o60_actorOps");
+ a = (ActorHE *)derefActorSafe(_curActor, "o60_actorOps");
if (!a)
return;
diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp
index 3f22c16648..577e7c3d99 100644
--- a/engines/scumm/he/script_v70he.cpp
+++ b/engines/scumm/he/script_v70he.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "common/config-manager.h"
#include "common/system.h"
@@ -546,6 +544,7 @@ void ScummEngine_v70he::o70_resourceRoutines() {
_res->unlock(rtRoomImage, resid);
break;
case 116:
+ // TODO: Clear Heap
break;
case 117: // SO_LOAD_CHARSET
resid = pop();
@@ -634,10 +633,10 @@ void ScummEngine_v70he::o70_systemOps() {
break;
case 160:
// Confirm shutdown
- shutDown();
+ quitGame();
break;
case 244:
- shutDown();
+ quitGame();
break;
case 250:
id = pop();
diff --git a/engines/scumm/he/script_v71he.cpp b/engines/scumm/he/script_v71he.cpp
index 8b2823aa8c..1338ab3db8 100644
--- a/engines/scumm/he/script_v71he.cpp
+++ b/engines/scumm/he/script_v71he.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "scumm/actor.h"
#include "scumm/he/intern_he.h"
#include "scumm/scumm.h"
@@ -500,7 +498,7 @@ void ScummEngine_v71he::adjustRect(Common::Rect &rect) {
void ScummEngine_v71he::o71_kernelSetFunctions() {
int args[29];
int num;
- Actor *a;
+ ActorHE *a;
num = getStackList(args, ARRAYSIZE(args));
@@ -511,8 +509,8 @@ void ScummEngine_v71he::o71_kernelSetFunctions() {
virtScreenLoad(args[1], args[2], args[3], args[4], args[5]);
break;
case 20: // HE72+
- a = derefActor(args[1], "o71_kernelSetFunctions: 20");
- ((ScummEngine_v71he *)this)->queueAuxBlock(a);
+ a = (ActorHE *)derefActor(args[1], "o71_kernelSetFunctions: 20");
+ queueAuxBlock(a);
break;
case 21:
_skipDrawObject = 1;
@@ -533,14 +531,14 @@ void ScummEngine_v71he::o71_kernelSetFunctions() {
redrawAllActors();
break;
case 26:
- a = derefActor(args[1], "o71_kernelSetFunctions: 26");
+ a = (ActorHE *)derefActor(args[1], "o71_kernelSetFunctions: 26");
a->_auxBlock.r.left = 0;
a->_auxBlock.r.right = -1;
a->_auxBlock.r.top = 0;
a->_auxBlock.r.bottom = -2;
break;
case 30:
- a = derefActor(args[1], "o71_kernelSetFunctions: 30");
+ a = (ActorHE *)derefActor(args[1], "o71_kernelSetFunctions: 30");
a->_clipOverride.bottom = args[2];
break;
case 42:
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index 6c3d0023d8..2fecc58bff 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "common/config-manager.h"
#include "common/savefile.h"
#include "common/system.h"
@@ -1021,7 +1019,7 @@ void ScummEngine_v72he::o72_roomOps() {
}
void ScummEngine_v72he::o72_actorOps() {
- Actor *a;
+ ActorHE *a;
int i, j, k;
int args[32];
byte string[256];
@@ -1032,7 +1030,7 @@ void ScummEngine_v72he::o72_actorOps() {
return;
}
- a = derefActorSafe(_curActor, "o72_actorOps");
+ a = (ActorHE *)derefActorSafe(_curActor, "o72_actorOps");
if (!a)
return;
@@ -1485,10 +1483,10 @@ void ScummEngine_v72he::o72_systemOps() {
break;
case 160:
// Confirm shutdown
- shutDown();
+ quitGame();
break;
case 244:
- shutDown();
+ quitGame();
break;
case 251:
copyScriptString(string, sizeof(string));
@@ -1635,13 +1633,10 @@ void ScummEngine_v72he::o72_drawWizImage() {
_wiz->displayWizImage(&wi);
}
-void ScummEngine_v72he::o72_debugInput() {
- byte string[255];
+void ScummEngine_v72he::debugInput(byte* string) {
byte *debugInputString;
- copyScriptString(string, sizeof(string));
-
- DebugInputDialog dialog(this, (char*)string);
+ DebugInputDialog dialog(this, (char *)string);
runDialog(dialog);
while (!dialog.done) {
parseEvents();
@@ -1654,6 +1649,13 @@ void ScummEngine_v72he::o72_debugInput() {
push(readVar(0));
}
+void ScummEngine_v72he::o72_debugInput() {
+ byte string[255];
+
+ copyScriptString(string, sizeof(string));
+ debugInput(string);
+}
+
void ScummEngine_v72he::o72_jumpToScript() {
int args[25];
int script;
diff --git a/engines/scumm/he/script_v80he.cpp b/engines/scumm/he/script_v80he.cpp
index 39ec715d94..46449d1683 100644
--- a/engines/scumm/he/script_v80he.cpp
+++ b/engines/scumm/he/script_v80he.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "common/config-file.h"
#include "common/config-manager.h"
#include "common/savefile.h"
@@ -646,7 +644,7 @@ void ScummEngine_v80he::drawLine(int x1, int y1, int x, int y, int step, int typ
if (type == 2) {
- Actor *a = derefActor(id, "drawLine");
+ ActorHE *a = (ActorHE *)derefActor(id, "drawLine");
a->drawActorToBackBuf(x, y);
} else if (type == 3) {
WizImage wi;
@@ -697,7 +695,7 @@ void ScummEngine_v80he::drawLine(int x1, int y1, int x, int y, int step, int typ
continue;
if (type == 2) {
- Actor *a = derefActor(id, "drawLine");
+ ActorHE *a = (ActorHE *)derefActor(id, "drawLine");
a->drawActorToBackBuf(x, y);
} else if (type == 3) {
WizImage wi;
diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp
index 37ce17c050..9829d0ecb5 100644
--- a/engines/scumm/he/script_v90he.cpp
+++ b/engines/scumm/he/script_v90he.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "scumm/actor.h"
#include "scumm/charset.h"
#include "scumm/he/animation_he.h"
@@ -395,42 +393,41 @@ void ScummEngine_v90he::o90_wizImageOps() {
int a, b;
int subOp = fetchScriptByte();
- subOp -= 46;
switch (subOp) {
- case -14: // HE99+
+ case 32: // HE99+
_wizParams.processFlags |= kWPFUseDefImgWidth;
_wizParams.resDefImgW = pop();
break;
- case -13: // HE99+
+ case 33: // HE99+
_wizParams.processFlags |= kWPFUseDefImgHeight;
_wizParams.resDefImgH = pop();
break;
- case 0:
+ case 46:
// Dummy case
pop();
break;
- case 1:
+ case 47:
_wizParams.box.bottom = pop();
_wizParams.box.right = pop();
_wizParams.box.top = pop();
_wizParams.box.left = pop();
break;
- case 2:
+ case 48:
_wizParams.processMode = 1;
break;
- case 3:
+ case 49:
_wizParams.processFlags |= kWPFUseFile;
_wizParams.processMode = 3;
copyScriptString(_wizParams.filename, sizeof(_wizParams.filename));
break;
- case 4:
+ case 50:
_wizParams.processFlags |= kWPFUseFile;
_wizParams.processMode = 4;
copyScriptString(_wizParams.filename, sizeof(_wizParams.filename));
_wizParams.fileWriteMode = pop();
break;
- case 5:
+ case 51:
_wizParams.processFlags |= kWPFClipBox | 0x100;
_wizParams.processMode = 2;
_wizParams.box.bottom = pop();
@@ -440,19 +437,19 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.compType = pop();
adjustRect(_wizParams.box);
break;
- case 6:
+ case 52:
_wizParams.processFlags |= kWPFNewState;
_wizParams.img.state = pop();
break;
- case 7:
+ case 53:
_wizParams.processFlags |= kWPFRotate;
_wizParams.angle = pop();
break;
- case 8:
+ case 54:
_wizParams.processFlags |= kWPFNewFlags;
_wizParams.img.flags |= pop();
break;
- case 10:
+ case 56:
_wizParams.img.flags = pop();
_wizParams.img.state = pop();
_wizParams.img.y1 = pop();
@@ -460,7 +457,7 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.img.resNum = pop();
_wiz->displayWizImage(&_wizParams.img);
break;
- case 11:
+ case 57:
_wizParams.img.resNum = pop();
_wizParams.processMode = 0;
_wizParams.processFlags = 0;
@@ -471,18 +468,18 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.spriteId = 0;
_wizParams.spriteGroup = 0;
break;
- case 16: // HE99+
+ case 62: // HE99+
_wizParams.processFlags |= kWPFMaskImg;
_wizParams.sourceImage = pop();
break;
- case 19:
- case 108:
+ case 65:
+ case 154:
_wizParams.processFlags |= kWPFSetPos;
_wizParams.img.y1 = pop();
_wizParams.img.x1 = pop();
break;
- case 20:
- case 203: // HE98+
+ case 66:
+ case 249: // HE98+
b = pop();
a = pop();
_wizParams.processFlags |= kWPFRemapPalette;
@@ -495,7 +492,7 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.remapColor[a] = b;
_wizParams.remapNum++;
break;
- case 21:
+ case 67:
_wizParams.processFlags |= kWPFClipBox;
_wizParams.box.bottom = pop();
_wizParams.box.right = pop();
@@ -503,26 +500,26 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.box.left = pop();
adjustRect(_wizParams.box);
break;
- case 40: // HE99+
+ case 86: // HE99+
_wizParams.processFlags |= kWPFPaletteNum;
_wizParams.img.palette = pop();
break;
- case 46:
+ case 92:
_wizParams.processFlags |= kWPFScaled;
_wizParams.scale = pop();
break;
- case 52:
+ case 98:
_wizParams.processFlags |= kWPFShadow;
_wizParams.img.shadow = pop();
break;
- case 85: // HE99+
+ case 131: // HE99+
_wizParams.processFlags |= 0x1000 | 0x100 | 0x2;
_wizParams.processMode = 7;
_wizParams.polygonId2 = pop();
_wizParams.polygonId1 = pop();
_wizParams.compType = pop();
break;
- case 87: // HE99+
+ case 133: // HE99+
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
_wizParams.processMode = 9;
_wizParams.fillColor = pop();
@@ -531,7 +528,7 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.box2.top = pop();
_wizParams.box2.left = pop();
break;
- case 88: // HE99+
+ case 134: // HE99+
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
_wizParams.processMode = 10;
_wizParams.fillColor = pop();
@@ -540,33 +537,33 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.box2.top = pop();
_wizParams.box2.left = pop();
break;
- case 89: // HE99+
+ case 135: // HE99+
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
_wizParams.processMode = 11;
_wizParams.fillColor = pop();
_wizParams.box2.top = _wizParams.box2.bottom = pop();
_wizParams.box2.left = _wizParams.box2.right = pop();
break;
- case 90: // HE99+
+ case 136: // HE99+
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
_wizParams.processMode = 12;
_wizParams.fillColor = pop();
_wizParams.box2.top = _wizParams.box2.bottom = pop();
_wizParams.box2.left = _wizParams.box2.right = pop();
break;
- case 91: // HE99+
+ case 137: // HE99+
_wizParams.processFlags |= kWPFDstResNum;
_wizParams.dstResNum = pop();
break;
- case 93: // HE99+
+ case 139: // HE99+
_wizParams.processFlags |= kWPFThickLine;
_wizParams.lineUnk1 = pop();
_wizParams.lineUnk2 = pop();
break;
- case 95: // HE99+
+ case 141: // HE99+
_wizParams.processMode = 13;
break;
- case 96: // HE99+
+ case 142: // HE99+
_wizParams.field_239D = pop();
_wizParams.field_2399 = pop();
_wizParams.field_23A5 = pop();
@@ -574,13 +571,13 @@ void ScummEngine_v90he::o90_wizImageOps() {
copyScriptString(_wizParams.string2, sizeof(_wizParams.string2));
_wizParams.processMode = 15;
break;
- case 97: // HE99+
+ case 143: // HE99+
_wizParams.processMode = 16;
_wizParams.field_23AD = pop();
_wizParams.field_23A9 = pop();
copyScriptString(_wizParams.string1, sizeof(_wizParams.string1));
break;
- case 143: // HE99+
+ case 189: // HE99+
_wizParams.processMode = 17;
_wizParams.field_23CD = pop();
_wizParams.field_23C9 = pop();
@@ -591,18 +588,18 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.field_23B5 = pop();
_wizParams.field_23B1 = pop();
break;
- case 150: // HE99+
+ case 196: // HE99+
_wizParams.processMode = 14;
break;
- case 171: // HE99+
+ case 217: // HE99+
_wizParams.processMode = 8;
break;
- case 200:
+ case 246:
_wizParams.processFlags |= kWPFNewFlags | kWPFSetPos | 2;
_wizParams.img.flags |= kWIFIsPolygon;
_wizParams.polygonId1 = _wizParams.img.y1 = _wizParams.img.x1 = pop();
break;
- case 209:
+ case 255:
if (_wizParams.img.resNum)
_wiz->processWizImage(&_wizParams);
break;
@@ -724,10 +721,9 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
int32 x, y;
byte subOp = fetchScriptByte();
- subOp -= 30;
switch (subOp) {
- case 0:
+ case 30:
spriteId = pop();
if (spriteId) {
_sprite->getSpritePosition(spriteId, x, y);
@@ -736,7 +732,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 1:
+ case 31:
spriteId = pop();
if (spriteId) {
_sprite->getSpritePosition(spriteId, x, y);
@@ -745,7 +741,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 2:
+ case 32:
spriteId = pop();
if (spriteId) {
_sprite->getSpriteImageDim(spriteId, x, y);
@@ -754,7 +750,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 3:
+ case 33:
spriteId = pop();
if (spriteId) {
_sprite->getSpriteImageDim(spriteId, x, y);
@@ -763,7 +759,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 4:
+ case 34:
spriteId = pop();
if (spriteId) {
_sprite->getSpriteDist(spriteId, x, y);
@@ -772,7 +768,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 5:
+ case 35:
spriteId = pop();
if (spriteId) {
_sprite->getSpriteDist(spriteId, x, y);
@@ -781,35 +777,35 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 6:
+ case 36:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteImageStateCount(spriteId));
else
push(0);
break;
- case 7:
+ case 37:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteGroup(spriteId));
else
push(0);
break;
- case 8:
+ case 38:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteDisplayX(spriteId));
else
push(0);
break;
- case 9:
+ case 39:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteDisplayY(spriteId));
else
push(0);
break;
- case 12:
+ case 42:
flags = pop();
spriteId = pop();
if (spriteId) {
@@ -836,14 +832,14 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 13:
+ case 43:
spriteId = pop();
if (spriteId)
push(_sprite->getSpritePriority(spriteId));
else
push(0);
break;
- case 15:
+ case 45:
if (_game.heversion == 99) {
flags = getStackList(args, ARRAYSIZE(args));
type = pop();
@@ -864,77 +860,77 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(_sprite->findSpriteWithClassOf(x, y, groupId, 0, 0, 0));
}
break;
- case 22:
+ case 52:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteImageState(spriteId));
else
push(0);
break;
- case 32:
+ case 62:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteSourceImage(spriteId));
else
push(0);
break;
- case 33:
+ case 63:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteImage(spriteId));
else
push(0);
break;
- case 38:
+ case 68:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteFlagEraseType(spriteId));
else
push(1);
break;
- case 52:
+ case 82:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteFlagAutoAnim(spriteId));
else
push(0);
break;
- case 56:
+ case 86:
spriteId = pop();
if (spriteId)
push(_sprite->getSpritePalette(spriteId));
else
push(0);
break;
- case 62:
+ case 92:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteScale(spriteId));
else
push(0);
break;
- case 67:
+ case 97:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteAnimSpeed(spriteId));
else
push(1);
break;
- case 68:
+ case 98:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteShadow(spriteId));
else
push(0);
break;
- case 94:
+ case 124:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteFlagUpdateType(spriteId));
else
push(0);
break;
- case 95:
+ case 125:
flags = getStackList(args, ARRAYSIZE(args));
spriteId = pop();
if (spriteId) {
@@ -943,7 +939,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
push(0);
}
break;
- case 109:
+ case 139:
flags = pop();
spriteId = pop();
if (spriteId)
@@ -951,14 +947,14 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
else
push(0);
break;
- case 110:
+ case 140:
spriteId = pop();
if (spriteId)
push(_sprite->getSpriteMaskImage(spriteId));
else
push(0);
break;
- case 168:
+ case 198:
pop();
spriteId = pop();
if (spriteId)
@@ -978,10 +974,9 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
int n;
byte subOp = fetchScriptByte();
- subOp -= 34;
switch (subOp) {
- case 0:
+ case 34:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -994,7 +989,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, args[0], tmp[1]);
}
break;
- case 1:
+ case 35:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1007,7 +1002,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, tmp[0], args[0]);
}
break;
- case 3:
+ case 37:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1018,7 +1013,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGroup(spriteId, args[0]);
break;
- case 8:
+ case 42:
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1048,7 +1043,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
break;
}
break;
- case 9:
+ case 43:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1059,7 +1054,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePriority(spriteId, args[0]);
break;
- case 10:
+ case 44:
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1071,7 +1066,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->moveSprite(spriteId, args[0], args[1]);
break;
- case 18:
+ case 52:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1082,7 +1077,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImageState(spriteId, args[0]);
break;
- case 19:
+ case 53:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1093,7 +1088,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAngle(spriteId, args[0]);
break;
- case 23:
+ case 57:
if (_game.features & GF_HE_985 || _game.heversion >= 99) {
_curMaxSpriteId = pop();
_curSpriteId = pop();
@@ -1105,7 +1100,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
_curMaxSpriteId = _curSpriteId; // to make all functions happy
}
break;
- case 28: // HE99+
+ case 62: // HE99+
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1116,7 +1111,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteSourceImage(spriteId, args[0]);
break;
- case 29:
+ case 63:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1127,7 +1122,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImage(spriteId, args[0]);
break;
- case 31:
+ case 65:
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1139,7 +1134,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePosition(spriteId, args[0], args[1]);
break;
- case 34:
+ case 68:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1150,7 +1145,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagEraseType(spriteId, args[0]);
break;
- case 43:
+ case 77:
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1162,7 +1157,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteDist(spriteId, args[0], args[1]);
break;
- case 48:
+ case 82:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1173,7 +1168,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagAutoAnim(spriteId, args[0]);
break;
- case 52: // HE 98+
+ case 86: // HE 98+
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1184,7 +1179,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePalette(spriteId, args[0]);
break;
- case 58: // HE 99+
+ case 92: // HE 99+
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1195,7 +1190,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteScale(spriteId, args[0]);
break;
- case 63: // HE 98+
+ case 97: // HE 98+
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1206,7 +1201,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAnimSpeed(spriteId, args[0]);
break;
- case 64:
+ case 98:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1217,7 +1212,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteShadow(spriteId, args[0]);
break;
- case 90:
+ case 124:
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1228,7 +1223,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagUpdateType(spriteId, args[0]);
break;
- case 91:
+ case 125:
n = getStackList(args, ARRAYSIZE(args));
if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) {
int *p = &args[n - 1];
@@ -1251,7 +1246,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
} while (--n);
}
break;
- case 105: // HE 99+
+ case 139: // HE 99+
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1263,7 +1258,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]);
break;
- case 106: // HE 99+
+ case 140: // HE 99+
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1274,10 +1269,10 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteMaskImage(spriteId, args[0]);
break;
- case 124:
+ case 158:
_sprite->resetTables(true);
break;
- case 164:
+ case 198:
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1289,7 +1284,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteUserValue(spriteId, args[0], args[1]);
break;
- case 183:
+ case 217:
if (_curSpriteId > _curMaxSpriteId)
break;
spriteId = _curSpriteId;
@@ -1389,10 +1384,9 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
int type, value1, value2, value3, value4;
byte subOp = fetchScriptByte();
- subOp -= 37;
switch (subOp) {
- case 0:
+ case 37:
type = pop() - 1;
switch (type) {
case 0:
@@ -1455,7 +1449,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
error("o90_setSpriteGroupInfo subOp 0: Unknown case %d", subOp);
}
break;
- case 5:
+ case 42:
type = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -1478,14 +1472,14 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
error("o90_setSpriteGroupInfo subOp 5: Unknown case %d", subOp);
}
break;
- case 6:
+ case 43:
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupPriority(_curSpriteGroupId, value1);
break;
- case 7:
+ case 44:
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -1493,17 +1487,17 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
_sprite->moveGroup(_curSpriteGroupId, value1, value2);
break;
- case 20:
+ case 57:
_curSpriteGroupId = pop();
break;
- case 26:
+ case 63:
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupImage(_curSpriteGroupId, value1);
break;
- case 28:
+ case 65:
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -1511,7 +1505,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
_sprite->setGroupPosition(_curSpriteGroupId, value1, value2);
break;
- case 30:
+ case 67:
value4 = pop();
value3 = pop();
value2 = pop();
@@ -1521,13 +1515,13 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
_sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4);
break;
- case 56:
+ case 93:
if (!_curSpriteGroupId)
break;
_sprite->resetGroupBounds(_curSpriteGroupId);
break;
- case 180:
+ case 217:
if (!_curSpriteGroupId)
break;
@@ -1545,52 +1539,51 @@ void ScummEngine_v90he::o90_getWizData() {
int32 x, y;
byte subOp = fetchScriptByte();
- subOp -= 30;
switch (subOp) {
- case 0:
+ case 30:
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(x);
break;
- case 1:
+ case 31:
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(y);
break;
- case 2:
+ case 32:
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(w);
break;
- case 3:
+ case 33:
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(h);
break;
- case 6:
+ case 36:
resId = pop();
push(_wiz->getWizImageStates(resId));
break;
- case 15:
+ case 45:
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0));
break;
- case 36:
+ case 66:
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->getWizPixelColor(resId, state, x, y, 0));
break;
- case 100:
+ case 130:
h = pop();
w = pop();
y = pop();
@@ -1604,12 +1597,12 @@ void ScummEngine_v90he::o90_getWizData() {
}
push(computeWizHistogram(resId, state, x, y, w, h));
break;
- case 109:
+ case 139:
pop();
pop();
push(0);
break;
- case 111:
+ case 141:
pop();
copyScriptString(filename, sizeof(filename));
pop();
@@ -1622,13 +1615,13 @@ void ScummEngine_v90he::o90_getWizData() {
}
void ScummEngine_v90he::o90_getActorData() {
- Actor *a;
+ ActorHE *a;
int subOp = pop();
int val = pop();
int act = pop();
- a = derefActor(act, "o90_getActorData");
+ a = (ActorHE *)derefActor(act, "o90_getActorData");
switch (subOp) {
case 1:
@@ -1730,30 +1723,29 @@ void ScummEngine_v90he::o90_videoOps() {
void ScummEngine_v90he::o90_getVideoData() {
// Uses Smacker video
byte subOp = fetchScriptByte();
- subOp -= 32;
switch (subOp) {
- case 0: // Get width
+ case 32: // Get width
pop();
push(_moviePlay->getWidth());
break;
- case 1: // Get height
+ case 33: // Get height
pop();
push(_moviePlay->getHeight());
break;
- case 4: // Get frame count
+ case 36: // Get frame count
pop();
push(_moviePlay->getFrameCount());
break;
- case 20: // Get current frame
+ case 52: // Get current frame
pop();
push(_moviePlay->getCurFrame());
break;
- case 31: // Get image number
+ case 63: // Get image number
pop();
push(_moviePlay->getImageNum());
break;
- case 107: // Get statistics
+ case 139: // Get statistics
debug(0, "o90_getVideoData: subOp 107 stub (%d, %d)", pop(), pop());
push(0);
break;
@@ -1764,33 +1756,32 @@ void ScummEngine_v90he::o90_getVideoData() {
void ScummEngine_v90he::o90_floodFill() {
byte subOp = fetchScriptByte();
- subOp -= 54;
switch (subOp) {
- case 0:
+ case 54:
pop();
break;
- case 3:
+ case 57:
memset(&_floodFillParams, 0, sizeof(_floodFillParams));
_floodFillParams.box.left = 0;
_floodFillParams.box.top = 0;
_floodFillParams.box.right = 639;
_floodFillParams.box.bottom = 479;
break;
- case 11:
+ case 65:
_floodFillParams.y = pop();
_floodFillParams.x = pop();
break;
- case 12:
+ case 66:
_floodFillParams.flags = pop();
break;
- case 13:
+ case 67:
_floodFillParams.box.bottom = pop();
_floodFillParams.box.right = pop();
_floodFillParams.box.top = pop();
_floodFillParams.box.left = pop();
break;
- case 201:
+ case 255:
floodFill(&_floodFillParams, this);
break;
default:
@@ -2336,47 +2327,46 @@ void ScummEngine_v90he::o90_sortArray() {
void ScummEngine_v90he::o90_getObjectData() {
byte subOp = fetchScriptByte();
- subOp -= 32;
switch (subOp) {
- case 0:
+ case 32:
if (_heObjectNum == -1)
push(0);
else
push(_objs[_heObjectNum].width);
break;
- case 1:
+ case 33:
if (_heObjectNum == -1)
push(0);
else
push(_objs[_heObjectNum].height);
break;
- case 4:
+ case 36:
if (_heObjectNum == -1)
push(0);
else
push(getObjectImageCount(_heObject));
break;
- case 6:
+ case 38:
if (_heObjectNum == -1)
push(0);
else
push(_objs[_heObjectNum].x_pos);
break;
- case 7:
+ case 39:
if (_heObjectNum == -1)
push(0);
else
push(_objs[_heObjectNum].y_pos);
break;
- case 20:
+ case 52:
push(getState(_heObject));
break;
- case 25:
+ case 57:
_heObject = pop();
_heObjectNum = getObjectIndex(_heObject);
break;
- case 107:
+ case 139:
// Dummy case
pop();
push(0);
@@ -2391,10 +2381,9 @@ void ScummEngine_v90he::o90_getPaletteData() {
int palSlot, color;
byte subOp = fetchScriptByte();
- subOp -= 45;
switch (subOp) {
- case 0:
+ case 45:
e = pop();
d = pop();
palSlot = pop();
@@ -2403,23 +2392,23 @@ void ScummEngine_v90he::o90_getPaletteData() {
b = pop();
push(getHEPaletteSimilarColor(palSlot, b, c, d, e));
break;
- case 7:
+ case 52:
c = pop();
b = pop();
palSlot = pop();
push(getHEPaletteColorComponent(palSlot, b, c));
break;
- case 21:
+ case 66:
color = pop();
palSlot = pop();
push(getHEPaletteColor(palSlot, color));
break;
- case 87:
+ case 132:
c = pop();
b = pop();
push(getHEPaletteColorComponent(1, b, c));
break;
- case 172:
+ case 217:
pop();
c = pop();
c = MAX(0, c);
@@ -2438,20 +2427,19 @@ void ScummEngine_v90he::o90_paletteOps() {
int a, b, c, d, e;
byte subOp = fetchScriptByte();
- subOp -= 57;
switch (subOp) {
- case 0:
+ case 57:
_hePaletteNum = pop();
break;
- case 6:
+ case 63:
b = pop();
a = pop();
if (_hePaletteNum != 0) {
setHEPaletteFromImage(_hePaletteNum, a, b);
}
break;
- case 9:
+ case 66:
e = pop();
d = pop();
c = pop();
@@ -2463,7 +2451,7 @@ void ScummEngine_v90he::o90_paletteOps() {
}
}
break;
- case 13:
+ case 70:
c = pop();
b = pop();
a = pop();
@@ -2473,31 +2461,31 @@ void ScummEngine_v90he::o90_paletteOps() {
}
}
break;
- case 19: //HE99+
+ case 76: //HE99+
a = pop();
if (_hePaletteNum != 0) {
setHEPaletteFromCostume(_hePaletteNum, a);
}
break;
- case 29:
+ case 86:
a = pop();
if (_hePaletteNum != 0) {
copyHEPalette(_hePaletteNum, a);
}
break;
- case 118:
+ case 175:
b = pop();
a = pop();
if (_hePaletteNum != 0) {
setHEPaletteFromRoom(_hePaletteNum, a, b);
}
break;
- case 160:
+ case 217:
if (_hePaletteNum != 0) {
restoreHEPalette(_hePaletteNum);
}
break;
- case 198:
+ case 255:
_hePaletteNum = 0;
break;
default:
@@ -2580,13 +2568,13 @@ void ScummEngine_v90he::o90_kernelGetFunctions() {
void ScummEngine_v90he::o90_kernelSetFunctions() {
int args[29];
int num, tmp;
- Actor *a;
+ ActorHE *a;
num = getStackList(args, ARRAYSIZE(args));
switch (args[0]) {
case 20:
- a = derefActor(args[1], "o90_kernelSetFunctions: 20");
+ a = (ActorHE *)derefActor(args[1], "o90_kernelSetFunctions: 20");
queueAuxBlock(a);
break;
case 21:
@@ -2628,7 +2616,7 @@ void ScummEngine_v90he::o90_kernelSetFunctions() {
// Remote start script function
break;
case 1969:
- a = derefActor(args[1], "o90_kernelSetFunctions: 1969");
+ a = (ActorHE *)derefActor(args[1], "o90_kernelSetFunctions: 1969");
tmp = a->_heCondMask;
tmp ^= args[2];
tmp &= 0x7FFF0000;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 35028c7e1c..bb67f2b31d 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -192,10 +192,6 @@ void ScummEngine::parseEvents() {
_keyPressed = Common::KeyState(Common::KEYCODE_6, 54); // '6'
break;
- case Common::EVENT_QUIT:
- _quit = true;
- break;
-
default:
break;
}
@@ -475,7 +471,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0);
- mainMenuDialog(); // Display NewGui
+ scummMenuDialog(); // Display NewGui
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0);
@@ -514,7 +510,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
vol = Audio::Mixer::kMaxMixerVolume;
ConfMan.setInt("music_volume", vol);
- updateSoundSettings();
+ syncSoundSettings();
} else if (lastKeyHit.ascii == '-' || lastKeyHit.ascii == '+') { // Change text speed
if (lastKeyHit.ascii == '+' && _defaultTalkDelay > 0)
@@ -527,7 +523,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
_defaultTalkDelay = 9 - runDialog(dlg);
// Save the new talkspeed value to ConfMan
- setTalkspeed(_defaultTalkDelay);
+ setTalkDelay(_defaultTalkDelay);
if (VAR_CHARINC != 0xFF)
VAR(VAR_CHARINC) = _defaultTalkDelay;
diff --git a/engines/scumm/insane/insane.cpp b/engines/scumm/insane/insane.cpp
index 1771618822..77a01d54d0 100644
--- a/engines/scumm/insane/insane.cpp
+++ b/engines/scumm/insane/insane.cpp
@@ -39,7 +39,6 @@
#include "scumm/smush/smush_player.h"
#include "scumm/smush/smush_font.h"
-#include "scumm/smush/chunk.h"
#include "scumm/insane/insane.h"
@@ -1310,33 +1309,25 @@ void Insane::smlayer_showStatusMsg(int32 arg_0, byte *renderBitmap, int32 codecp
free (string);
}
-void Insane::procSKIP(Chunk &b) {
+void Insane::procSKIP(int32 subSize, Common::SeekableReadStream &b) {
int16 par1, par2;
_player->_skipNext = false;
if ((_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC)) {
- _player->checkBlock(b, MKID_BE('SKIP'), 2);
+ assert(subSize >= 2);
par1 = b.readUint16LE();
- if (isBitSet(par1))
- _player->_skipNext = true;
- return;
+ par2 = 0;
+ } else {
+ assert(subSize >= 4);
+ par1 = b.readUint16LE();
+ par2 = b.readUint16LE();
}
- _player->checkBlock(b, MKID_BE('SKIP'), 4);
-
- par1 = b.readUint16LE();
- par2 = b.readUint16LE();
-
-
if (!par2) {
if (isBitSet(par1))
_player->_skipNext = true;
- return;
- }
-
- if (isBitSet(par1) != isBitSet(par2)) {
+ } else if (isBitSet(par1) != isBitSet(par2)) {
_player->_skipNext = true;
- return;
}
}
diff --git a/engines/scumm/insane/insane.h b/engines/scumm/insane/insane.h
index 28eafb6f73..50d8d057cf 100644
--- a/engines/scumm/insane/insane.h
+++ b/engines/scumm/insane/insane.h
@@ -31,7 +31,6 @@
#include "scumm/nut_renderer.h"
#include "scumm/smush/smush_player.h"
-#include "scumm/smush/chunk.h"
namespace Scumm {
@@ -67,9 +66,9 @@ class Insane {
void procPostRendering(byte *renderBitmap, int32 codecparam, int32 setupsan12,
int32 setupsan13, int32 curFrame, int32 maxFrame);
void procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags, int16 par1,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags, int16 par1,
int16 par2, int16 par3, int16 par4);
- void procSKIP(Chunk &b);
+ void procSKIP(int32 subSize, Common::SeekableReadStream &b);
void escapeKeyHandler(void);
private:
@@ -434,22 +433,22 @@ class Insane {
void ouchSoundEnemy(void);
bool weaponEnemyIsEffective(void);
void iactScene1(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4);
void iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 command, int16 par1, int16, int16);
void iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4);
void iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4);
void iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4);
void iactScene21(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4);
bool isBitSet(int n);
void setBit(int n);
diff --git a/engines/scumm/insane/insane_iact.cpp b/engines/scumm/insane/insane_iact.cpp
index c7f0c7220b..b6ce1091e8 100644
--- a/engines/scumm/insane/insane_iact.cpp
+++ b/engines/scumm/insane/insane_iact.cpp
@@ -30,14 +30,13 @@
#include "scumm/scumm.h"
#include "scumm/smush/smush_player.h"
-#include "scumm/smush/chunk.h"
#include "scumm/insane/insane.h"
namespace Scumm {
void Insane::procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
if (_keyboardDisable)
return;
@@ -67,7 +66,7 @@ void Insane::procIACT(byte *renderBitmap, int32 codecparam, int32 setupsan12,
}
void Insane::iactScene1(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
int16 par5, par6, par7, par9, par11, par13, tmp;
@@ -294,7 +293,7 @@ void Insane::removeEnemyFromMetList(int32 enemy1) {
}
void Insane::iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 command, int16 par1, int16, int16) {
int par2, par3;
if (command == 6) {
@@ -317,7 +316,7 @@ void Insane::iactScene3(byte *renderBitmap, int32 codecparam, int32 setupsan12,
}
void Insane::iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
int16 par5;
@@ -393,7 +392,7 @@ void Insane::iactScene4(byte *renderBitmap, int32 codecparam, int32 setupsan12,
}
void Insane::iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
int16 par5;
@@ -478,7 +477,7 @@ void Insane::iactScene6(byte *renderBitmap, int32 codecparam, int32 setupsan12,
}
void Insane::iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
switch (par1) {
case 2:
@@ -524,7 +523,7 @@ void Insane::iactScene17(byte *renderBitmap, int32 codecparam, int32 setupsan12,
}
void Insane::iactScene21(byte *renderBitmap, int32 codecparam, int32 setupsan12,
- int32 setupsan13, Chunk &b, int32 size, int32 flags,
+ int32 setupsan13, Common::SeekableReadStream &b, int32 size, int32 flags,
int16 par1, int16 par2, int16 par3, int16 par4) {
// void implementation
}
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 7d52a02116..8d6a5453df 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -53,7 +53,6 @@ MODULE_OBJS := \
scumm.o \
sound.o \
string.o \
- thumbnail.o \
usage_bits.o \
util.o \
vars.o \
@@ -82,7 +81,6 @@ MODULE_OBJS += \
insane/insane_scenes.o \
insane/insane_iact.o \
smush/channel.o \
- smush/chunk.o \
smush/codec1.o \
smush/codec37.o \
smush/codec47.o \
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index 8bcd92fd3b..eaffbd04bb 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -109,6 +109,13 @@ void ScummEngine::setOwnerOf(int obj, int owner) {
int arg = (_game.version >= 6) ? obj : 0;
+ // WORKAROUND for bug #1917981: Game crash when finishing Indy3 demo.
+ // Script 94 tries to empty the inventory but does so in a bogus way.
+ // This causes it to try to remove object 0 from the inventory.
+ if (_game.id == GID_PASS && obj == 0 && vm.slot[_currentScript].number == 94)
+ return;
+ assert(obj > 0);
+
if (owner == 0) {
clearOwnerOf(obj);
diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp
index 6bd62c1761..50e0d221ca 100644
--- a/engines/scumm/resource.cpp
+++ b/engines/scumm/resource.cpp
@@ -226,7 +226,7 @@ void ScummEngine::askForDisk(const char *filename, int disknum) {
#ifdef MACOSX
sprintf(buf, "Cannot find file: '%s'\nPlease insert disc %d.\nPress OK to retry, Quit to exit", filename, disknum);
#else
- sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataPath.c_str());
+ sprintf(buf, "Cannot find file: '%s'\nInsert disc %d into drive %s\nPress OK to retry, Quit to exit", filename, disknum, _gameDataDir.getPath().c_str());
#endif
result = displayMessage("Quit", buf);
@@ -253,7 +253,7 @@ void ScummEngine::readIndexFile() {
if (_game.version <= 5) {
// Figure out the sizes of various resources
- while (!_fileHandle->eof()) {
+ while (!_fileHandle->eos()) {
blocktype = _fileHandle->readUint32BE();
itemsize = _fileHandle->readUint32BE();
if (_fileHandle->ioFailed())
@@ -291,7 +291,7 @@ void ScummEngine::readIndexFile() {
if (checkTryMedia(_fileHandle)) {
displayMessage(NULL, "You're trying to run game encrypted by ActiveMark. This is not supported.");
- _quit = true;
+ quitGame();
return;
}
@@ -809,7 +809,7 @@ byte *ResourceManager::createResource(int type, int idx, uint32 size) {
ptr = (byte *)calloc(size + sizeof(MemBlkHeader) + SAFETY_AREA, 1);
if (ptr == NULL) {
- error("Out of memory while allocating %d", size);
+ error("createResource(%s,%d): Out of memory while allocating %d", resTypeFromId(type), idx, size);
}
_allocatedSize += size;
diff --git a/engines/scumm/resource_v4.cpp b/engines/scumm/resource_v4.cpp
index 0ced00e254..29d7c5d25d 100644
--- a/engines/scumm/resource_v4.cpp
+++ b/engines/scumm/resource_v4.cpp
@@ -62,7 +62,7 @@ void ScummEngine_v4::readIndexFile() {
closeRoom();
openRoom(0);
- while (!_fileHandle->eof()) {
+ while (!_fileHandle->eos()) {
// Figure out the sizes of various resources
itemsize = _fileHandle->readUint32LE();
blocktype = _fileHandle->readUint16LE();
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index f9e4eb415c..267e06dafd 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -46,6 +46,8 @@
#include "sound/audiocd.h"
#include "sound/mixer.h"
+#include "graphics/thumbnail.h"
+
namespace Scumm {
struct SaveGameHeader {
@@ -71,6 +73,8 @@ struct SaveInfoSection {
#define INFOSECTION_VERSION 2
+#pragma mark -
+
void ScummEngine::requestSave(int slot, const char *name, bool temporary) {
_saveLoadSlot = slot;
_saveTemporaryState = temporary;
@@ -99,34 +103,36 @@ static bool saveSaveGameHeader(Common::OutSaveFile *out, SaveGameHeader &hdr) {
}
bool ScummEngine::saveState(int slot, bool compat) {
- char filename[256];
+ Common::String filename;
Common::OutSaveFile *out;
SaveGameHeader hdr;
if (_saveLoadSlot == 255) {
// Allow custom filenames for save game system in HE Games
- memcpy(filename, _saveLoadFileName, sizeof(_saveLoadFileName));
+ filename = _saveLoadFileName;
} else {
- makeSavegameName(filename, slot, compat);
+ filename = makeSavegameName(slot, compat);
}
- if (!(out = _saveFileMan->openForSaving(filename)))
+ if (!(out = _saveFileMan->openForSaving(filename.c_str())))
return false;
memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
saveSaveGameHeader(out, hdr);
- saveThumbnail(out);
+#if !defined(__DS__)
+ Graphics::saveThumbnail(*out);
+#endif
saveInfos(out);
Serializer ser(0, out, CURRENT_VER);
saveOrLoad(&ser);
out->finalize();
- if (out->ioFailed()) {
+ if (out->err()) {
delete out;
- debug(1, "State save as '%s' FAILED", filename);
+ debug(1, "State save as '%s' FAILED", filename.c_str());
return false;
}
delete out;
- debug(1, "State saved as '%s'", filename);
+ debug(1, "State saved as '%s'", filename.c_str());
return true;
}
@@ -135,11 +141,11 @@ static bool loadSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &h
hdr.size = in->readUint32LE();
hdr.ver = in->readUint32LE();
in->read(hdr.name, sizeof(hdr.name));
- return !in->ioFailed() && hdr.type == MKID_BE('SCVM');
+ return !in->err() && hdr.type == MKID_BE('SCVM');
}
bool ScummEngine::loadState(int slot, bool compat) {
- char filename[256];
+ Common::String filename;
Common::SeekableReadStream *in;
int i, j;
SaveGameHeader hdr;
@@ -147,15 +153,15 @@ bool ScummEngine::loadState(int slot, bool compat) {
if (_saveLoadSlot == 255) {
// Allow custom filenames for save game system in HE Games
- memcpy(filename, _saveLoadFileName, sizeof(_saveLoadFileName));
+ filename = _saveLoadFileName;
} else {
- makeSavegameName(filename, slot, compat);
+ filename = makeSavegameName(slot, compat);
}
- if (!(in = _saveFileMan->openForLoading(filename)))
+ if (!(in = _saveFileMan->openForLoading(filename.c_str())))
return false;
if (!loadSaveGameHeader(in, hdr)) {
- warning("Invalid savegame '%s'", filename);
+ warning("Invalid savegame '%s'", filename.c_str());
delete in;
return false;
}
@@ -171,30 +177,30 @@ bool ScummEngine::loadState(int slot, bool compat) {
// to work around a bug from the stone age (see below for more
// information).
if (hdr.ver < VER(7) || hdr.ver > CURRENT_VER) {
- warning("Invalid version of '%s'", filename);
+ warning("Invalid version of '%s'", filename.c_str());
delete in;
return false;
}
// We (deliberately) broke HE savegame compatibility at some point.
if (hdr.ver < VER(50) && _game.heversion >= 71) {
- warning("Unsupported version of '%s'", filename);
+ warning("Unsupported version of '%s'", filename.c_str());
delete in;
return false;
}
// Since version 52 a thumbnail is saved directly after the header.
if (hdr.ver >= VER(52)) {
- uint32 type = in->readUint32BE();
- // Check for the THMB header. Also, work around a bug which caused
- // the chunk type (incorrectly) to be written in LE on LE machines.
- if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){
- warning("Can not load thumbnail");
- delete in;
- return false;
+ // Prior to version 75 we always required an thumbnail to be present
+ if (hdr.ver <= VER(74)) {
+ if (!Graphics::checkThumbnailHeader(*in)) {
+ warning("Can not load thumbnail");
+ delete in;
+ return false;
+ }
}
- uint32 size = in->readUint32BE();
- in->skip(size - 8);
+
+ Graphics::skipThumbnailHeader(*in);
}
// Since version 56 we save additional information about the creation of
@@ -275,7 +281,7 @@ bool ScummEngine::loadState(int slot, bool compat) {
delete in;
// Update volume settings
- updateSoundSettings();
+ syncSoundSettings();
// Init NES costume data
if (_game.platform == Common::kPlatformNES) {
@@ -385,7 +391,7 @@ bool ScummEngine::loadState(int slot, bool compat) {
if (VAR_VOICE_MODE != 0xFF)
VAR(VAR_VOICE_MODE) = ConfMan.getBool("subtitles");
- debug(1, "State loaded from '%s'", filename);
+ debug(1, "State loaded from '%s'", filename.c_str());
_sound->pauseSounds(false);
@@ -401,23 +407,24 @@ bool ScummEngine::loadState(int slot, bool compat) {
return true;
}
-void ScummEngine::makeSavegameName(char *out, int slot, bool temporary) {
- sprintf(out, "%s.%c%.2d", _targetName.c_str(), temporary ? 'c' : 's', slot);
+Common::String ScummEngine::makeSavegameName(const Common::String &target, int slot, bool temporary) {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".%c%02d", temporary ? 'c' : 's', slot);
+ return (target + extension);
}
void ScummEngine::listSavegames(bool *marks, int num) {
assert(marks);
- char prefix[256];
char slot[3];
int slotNum;
Common::StringList files;
- makeSavegameName(prefix, 99, false);
- prefix[strlen(prefix)-2] = '*';
- prefix[strlen(prefix)-1] = 0;
+ Common::String prefix = makeSavegameName(99, false);
+ prefix.setChar('*', prefix.size()-2);
+ prefix.setChar(0, prefix.size()-1);
memset(marks, false, num * sizeof(bool)); //assume no savegames for this title
- files = _saveFileMan->listSavefiles(prefix);
+ files = _saveFileMan->listSavefiles(prefix.c_str());
for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) {
//Obtain the last 2 digits of the filename, since they correspond to the save slot
@@ -436,11 +443,10 @@ bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion
bool ScummEngine::getSavegameName(int slot, Common::String &desc) {
Common::InSaveFile *in = 0;
bool result = false;
- char filename[256];
desc.clear();
- makeSavegameName(filename, slot, false);
- in = _saveFileMan->openForLoading(filename);
+ Common::String filename = makeSavegameName(slot, false);
+ in = _saveFileMan->openForLoading(filename.c_str());
if (in) {
result = Scumm::getSavegameName(in, desc, _game.heversion);
delete in;
@@ -474,13 +480,15 @@ bool getSavegameName(Common::InSaveFile *in, Common::String &desc, int heversion
return true;
}
-Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) {
- char filename[256];
+Graphics::Surface *ScummEngine::loadThumbnailFromSlot(const char *target, int slot) {
Common::SeekableReadStream *in;
SaveGameHeader hdr;
- makeSavegameName(filename, slot, false);
- if (!(in = _saveFileMan->openForLoading(filename))) {
+ if (slot < 0)
+ return 0;
+
+ Common::String filename = ScummEngine::makeSavegameName(target, slot, false);
+ if (!(in = g_system->getSavefileManager()->openForLoading(filename.c_str()))) {
return 0;
}
@@ -496,19 +504,29 @@ Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) {
return 0;
}
- Graphics::Surface *thumb = loadThumbnail(in);
+ Graphics::Surface *thumb = 0;
+ if (Graphics::checkThumbnailHeader(*in)) {
+ thumb = new Graphics::Surface();
+ assert(thumb);
+ if (!Graphics::loadThumbnail(*in, *thumb)) {
+ delete thumb;
+ thumb = 0;
+ }
+ }
delete in;
return thumb;
}
-bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) {
- char filename[256];
+bool ScummEngine::loadInfosFromSlot(const char *target, int slot, InfoStuff *stuff) {
Common::SeekableReadStream *in;
SaveGameHeader hdr;
- makeSavegameName(filename, slot, false);
- if (!(in = _saveFileMan->openForLoading(filename))) {
+ if (slot < 0)
+ return 0;
+
+ Common::String filename = makeSavegameName(target, slot, false);
+ if (!(in = g_system->getSavefileManager()->openForLoading(filename.c_str()))) {
return false;
}
@@ -524,16 +542,8 @@ bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) {
return false;
}
- uint32 type = in->readUint32BE();
-
- // Check for the THMB header. Also, work around a bug which caused
- // the chunk type (incorrectly) to be written in LE on LE machines.
- if (! (type == MKID_BE('THMB') || (hdr.ver < VER(55) && type == MKID_BE('BMHT')))){
- delete in;
+ if (!Graphics::skipThumbnailHeader(*in))
return false;
- }
- uint32 size = in->readUint32BE();
- in->skip(size - 8);
if (!loadInfos(in, stuff)) {
delete in;
@@ -588,14 +598,13 @@ bool ScummEngine::loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff)
stuff->playtime = section.playtime;
// Skip over the remaining (unsupported) data
- if (section.size > SaveInfoSectionSize) {
+ if (section.size > SaveInfoSectionSize)
file->skip(section.size - SaveInfoSectionSize);
- }
return true;
}
-void ScummEngine::saveInfos(Common::OutSaveFile* file) {
+void ScummEngine::saveInfos(Common::WriteStream* file) {
SaveInfoSection section;
section.type = MKID_BE('INFO');
section.version = INFOSECTION_VERSION;
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index 0ddb4e5d2a..4f9899f961 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -31,7 +31,7 @@
namespace Common {
class SeekableReadStream;
- class OutSaveFile;
+ class WriteStream;
}
namespace Scumm {
@@ -50,7 +50,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 73
+#define CURRENT_VER 75
/**
* An auxillary macro, used to specify savegame versions. We use this instead
@@ -125,7 +125,7 @@ struct SaveLoadEntry {
class Serializer {
public:
- Serializer(Common::SeekableReadStream *in, Common::OutSaveFile *out, uint32 savegameVersion)
+ Serializer(Common::SeekableReadStream *in, Common::WriteStream *out, uint32 savegameVersion)
: _loadStream(in), _saveStream(out),
_savegameVersion(savegameVersion)
{ }
@@ -151,7 +151,7 @@ public:
protected:
Common::SeekableReadStream *_loadStream;
- Common::OutSaveFile *_saveStream;
+ Common::WriteStream *_saveStream;
uint32 _savegameVersion;
void saveArrayOf(void *b, int len, int datasize, byte filetype);
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 9268768f2e..642627d649 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -625,10 +625,10 @@ void ScummEngine::writeVar(uint var, int value) {
if (var == VAR_CHARINC) {
if (ConfMan.hasKey("talkspeed")) {
- value = getTalkspeed();
+ value = getTalkDelay();
} else {
// Save the new talkspeed value to ConfMan
- setTalkspeed(value);
+ setTalkDelay(value);
}
}
@@ -769,14 +769,14 @@ void ScummEngine::runInventoryScript(int i) {
args[0] = i;
if (VAR(VAR_INVENTORY_SCRIPT)) {
if (_game.id == GID_INDY3 && _game.platform == Common::kPlatformMacintosh) {
- inventoryScript();
+ inventoryScriptIndy3Mac();
} else {
runScript(VAR(VAR_INVENTORY_SCRIPT), 0, 0, args);
}
}
}
-void ScummEngine::inventoryScript() {
+void ScummEngine::inventoryScriptIndy3Mac() {
VerbSlot *vs;
int args[24];
int j, slot;
@@ -1201,11 +1201,11 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) {
if (clickArea == kVerbClickArea && (val >= 101 && val <= 108)) {
if (val == 107) {
VAR(67) -= 2;
- inventoryScript();
+ inventoryScriptIndy3Mac();
return;
} else if (val == 108) {
VAR(67) += 2;
- inventoryScript();
+ inventoryScriptIndy3Mac();
return;
} else {
args[0] = 3;
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 431321f459..c5c055249e 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1402,7 +1402,7 @@ void ScummEngine_v5::o5_ifClassOfIs() {
while ((_opcode = fetchScriptByte()) != 0xFF) {
cls = getVarOrDirectWord(PARAM_1);
b = getClass(act, cls);
- if (cls & 0x80 && !b || !(cls & 0x80) && b)
+ if (((cls & 0x80) && !b) || (!(cls & 0x80) && b))
cond = false;
}
if (cond)
@@ -1769,7 +1769,7 @@ void ScummEngine_v5::o5_systemOps() {
pauseGame();
break;
case 3: // SO_QUIT
- shutDown();
+ quitGame();
break;
default:
error("o5_systemOps: unknown subopcode %d", subOp);
diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
index 04ea53137b..c8534396db 100644
--- a/engines/scumm/script_v6.cpp
+++ b/engines/scumm/script_v6.cpp
@@ -2310,7 +2310,7 @@ void ScummEngine_v6::o6_systemOps() {
pauseGame();
break;
case 160: // SO_QUIT
- shutDown();
+ quitGame();
break;
default:
error("o6_systemOps invalid case %d", subOp);
@@ -2374,7 +2374,7 @@ void ScummEngine_v6::o6_printEgo() {
void ScummEngine_v6::o6_talkActor() {
int offset = _scriptPointer - _scriptOrgPointer;
- // WORKAROUNDfor bug #896489: see below for detailed description
+ // WORKAROUND for bug #896489: see below for detailed description
if (_forcedWaitForMessage) {
if (VAR(VAR_HAVE_MSG)) {
_scriptPointer--;
@@ -2390,6 +2390,15 @@ void ScummEngine_v6::o6_talkActor() {
_actorToPrintStrFor = pop();
+ // WORKAROUND for bug #2016521: "DOTT: Bernard impersonating LaVerne"
+ // Original script did not check for VAR_EGO == 2 before executing
+ // a talkActor opcode.
+ if (_game.id == GID_TENTACLE && vm.slot[_currentScript].number == 307
+ && VAR(VAR_EGO) != 2 && _actorToPrintStrFor == 2) {
+ _scriptPointer += resStrLen(_scriptPointer) + 1;
+ return;
+ }
+
_string[0].loadDefault();
actorTalk(_scriptPointer);
diff --git a/engines/scumm/script_v8.cpp b/engines/scumm/script_v8.cpp
index 08629afb07..8859435dc9 100644
--- a/engines/scumm/script_v8.cpp
+++ b/engines/scumm/script_v8.cpp
@@ -424,10 +424,10 @@ void ScummEngine_v8::writeVar(uint var, int value) {
if (var == VAR_CHARINC) {
if (ConfMan.hasKey("talkspeed")) {
- value = getTalkspeed();
+ value = getTalkDelay();
} else {
// Save the new talkspeed value to ConfMan
- setTalkspeed(value);
+ setTalkDelay(value);
}
}
@@ -1170,7 +1170,7 @@ void ScummEngine_v8::o8_systemOps() {
restart();
break;
case 0x29: // SO_SYSTEM_QUIT Quit game
- shutDown();
+ quitGame();
break;
default:
error("o8_systemOps: invalid case 0x%x", subOp);
@@ -1289,7 +1289,7 @@ void ScummEngine_v8::o8_kernelSetFunctions() {
if (ConfMan.getBool("confirm_exit"))
confirmExitDialog();
else
- _quit = true;
+ quitGame();
break;
case 108: // buildPaletteShadow
setShadowPalette(args[1], args[2], args[3], args[4], args[5], args[6]);
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index ce8f0a4d9a..b220779c55 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Mon Jul 28 00:13:01 2008
+ This file was generated by the md5table tool on Tue Sep 23 12:32:31 2008
DO NOT EDIT MANUALLY!
*/
@@ -54,6 +54,7 @@ static const MD5Table md5table[] = {
{ "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", 30919, Common::EN_USA, Common::kPlatformWindows },
{ "0f6f2e716ba896a44e5059bba1de7ca9", "samnmax", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown },
{ "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", -1, Common::FR_FRA, Common::kPlatformAtariST },
+ { "0f9d3317910ac7a9f449243118884ada", "puttzoo", "", "", 42070, Common::DE_DEU, Common::kPlatformWindows },
{ "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", 9080, Common::DE_DEU, Common::kPlatformUnknown },
{ "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", -1, Common::UNK_LANG, Common::kPlatformWindows },
{ "100b4c8403ad6a83d4bf7dbf83e44dc4", "spyfox", "", "", -1, Common::FR_FRA, Common::kPlatformWindows },
@@ -63,6 +64,7 @@ static const MD5Table md5table[] = {
{ "11e6e244078ff09b0f3832e35420e0a7", "catalog", "", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "132bff65e6367c09cc69318ce1b59333", "monkey2", "", "", 11155, Common::EN_ANY, Common::kPlatformAmiga },
{ "1387d16aa620dc1c2d1fd87f8a9e7a09", "puttcircus", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
+ { "13d2a86a7290813a1c386490447d72db", "fbear", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO },
{ "145bd3373574feb668cc2eea2ec6cf86", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "14d48c95b43ddeb983254cf6c43851f1", "freddi4", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformWindows },
@@ -98,6 +100,7 @@ static const MD5Table md5table[] = {
{ "1ff5997c78fbd0a841a75ef15a05d9d5", "BluesBirthday", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "2012f854d83d9cc6f73b2b544cd8bbf8", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "20176076d708bf14407bcc9bdcd7a418", "pajama3", "", "", -1, Common::RU_RUS, Common::kPlatformWindows },
+ { "204453e33456c4faa26e276229fe5b76", "spyfox2", "", "Demo", 14689, Common::DE_DEU, Common::kPlatformWindows },
{ "20da6fce37805423966aaa8f3c2426aa", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformAmiga },
{ "2108d83dcf09f8adb4bc524669c8cf51", "PuttTime", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "21a6592322f92550f144f68a8a4e685e", "dig", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
@@ -106,6 +109,7 @@ static const MD5Table md5table[] = {
{ "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "22d07d6c386c9c25aca5dac2a0c0d94b", "maniac", "NES", "", 262144, Common::SE_SWE, Common::kPlatformNES },
+ { "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows },
{ "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },
{ "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", 262144, Common::DE_DEU, Common::kPlatformNES },
@@ -144,6 +148,7 @@ static const MD5Table md5table[] = {
{ "362c1d281fb9899254cda66ad246c66a", "dig", "Demo", "Demo", 3472, Common::EN_ANY, Common::kPlatformUnknown },
{ "3686cf8f89e102ececf4366e1d2c8126", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformPC },
{ "36a6750e03fb505fc19fc2bf3e4dbe91", "pajama2", "", "Demo", 58749, Common::EN_ANY, Common::kPlatformUnknown },
+ { "3769b56c9a22f5521d74525ee459f88d", "puttrace", "HE 99", "Demo", 13108, Common::DE_DEU, Common::kPlatformWindows },
{ "37aed3f91c1ef959e0bd265f9b13781f", "pajama", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformPC },
{ "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows },
@@ -201,6 +206,7 @@ static const MD5Table md5table[] = {
{ "4edbf9d03550f7ba01e7f34d69b678dd", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "4f04b321a95d4315ce6d65f8e1dd0368", "maze", "HE 80", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "4f138ac6f9b2ac5a41bc68b2c3296064", "freddi4", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows },
+ { "4f1d6f8b38343dba405472538b5037ed", "fbear", "HE 61", "", 7717, Common::EN_ANY, Common::kPlatformPC },
{ "4f267a901719623de7dde83e47d5b474", "atlantis", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga },
{ "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },
{ "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformWindows },
@@ -208,6 +214,7 @@ static const MD5Table md5table[] = {
{ "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "5057fb0e99e5aa29df1836329232f101", "freddi2", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows },
{ "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows },
+ { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii },
{ "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformPC },
{ "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "513f91a9dbe8d5490b39e56a3ac5bbdf", "pajama2", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
@@ -219,8 +226,10 @@ static const MD5Table md5table[] = {
{ "55d3987641bf229c83bc729210173383", "zak", "V1", "", -1, Common::EN_ANY, Common::kPlatformC64 },
{ "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown },
{ "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", 9800, Common::EN_ANY, Common::kPlatformWindows },
+ { "5719fc8a13b4638b78d9d8d12f091f94", "puttrace", "HE 98.5", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "5798972220cd458be2626d54c80f71d7", "atlantis", "", "Floppy", -1, Common::IT_ITA, Common::kPlatformAmiga },
{ "57a17febe2183f521250e55d55b83e60", "PuttTime", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformWindows },
+ { "57a5cfec9ef231a007043cc1917e8988", "freddi", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii },
{ "57b0d89af79befe1cabce3bece869e7f", "tentacle", "", "Floppy", -1, Common::DE_DEU, Common::kPlatformPC },
{ "58436e634f4fae1d9973591c2ffa1fcb", "spyfox", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "589601b676c98b1c0c987bc031ab68b3", "chase", "HE 95", "", -1, Common::EN_USA, Common::kPlatformUnknown },
@@ -244,6 +253,7 @@ static const MD5Table md5table[] = {
{ "6269b8fbf51a353e5b501e4ad98cdc67", "arttime", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "6271130f440066830eca9056c1d7926f", "water", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "62b8c16b6db226ba95aaa8be73f9885c", "indy3", "EGA", "EGA", -1, Common::ES_ESP, Common::kPlatformAmiga },
+ { "632d2fddb8ba97723fa15334763ae857", "thinker1", "", "", 33270, Common::EN_ANY, Common::kPlatformWindows },
{ "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 85", "", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "6508fd55530e6915507e1cc37f7f045d", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },
{ "65563295c3a06493351870f20a1630cf", "spyozon", "HE CUP", "Preview", 5235008, Common::UNK_LANG, Common::kPlatformUnknown },
@@ -272,6 +282,7 @@ static const MD5Table md5table[] = {
{ "6b27dbcd8d5697d5c918eeca0f68ef6a", "puttrace", "HE CUP", "Preview", 3901484, Common::UNK_LANG, Common::kPlatformUnknown },
{ "6b3ec67da214f558dc5ceaa2acd47453", "indy3", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },
{ "6b5a3fef241e90d4b2e77f1e222773ee", "maniac", "NES", "extracted", -1, Common::SE_SWE, Common::kPlatformNES },
+ { "6bca7a1a96d16e52b8f3c42b50dbdca3", "fbear", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO },
{ "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows },
{ "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga },
{ "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh },
@@ -296,14 +307,17 @@ static const MD5Table md5table[] = {
{ "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformPC },
{ "7410a8ba9795020cd42f171c4320659e", "pajama3", "", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows },
+ { "74da3494fbe1a7d20213b0afe0954755", "catalog", "HE CUP", "Preview", 10841544, Common::FR_FRA, Common::kPlatformUnknown },
{ "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC },
{ "75bff95816b84672b877d22a911ab811", "freddi3", "HE 99", "Updated", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "76b66b43e593ad4d2f1dfb5cc8f19700", "spyfox", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "771bc18ec6f93837b839c992b211904b", "monkey", "Demo", "EGA Demo", -1, Common::DE_DEU, Common::kPlatformPC },
+ { "7766c9487f9d53a8cb0edabda5119c3d", "puttputt", "HE 60", "", 8022, Common::EN_ANY, Common::kPlatformPC },
{ "77f5c9cc0986eb729c1a6b4c8823bbae", "zak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns },
{ "780e4a0ae2ff17dc296f4a79543b44f8", "puttmoon", "", "", -1, Common::UNK_LANG, Common::kPlatformPC },
{ "782393c5934ecd0b536eaf5fd541bd26", "pajama", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
+ { "784b499c98d07260a30952685758636b", "pajama3", "", "Demo", 13911, Common::DE_DEU, Common::kPlatformWindows },
{ "78bd5f036ea35a878b74e4f47941f784", "freddi4", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown },
{ "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformPC },
@@ -322,6 +336,7 @@ static const MD5Table md5table[] = {
{ "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", 262144, Common::FR_FRA, Common::kPlatformNES },
{ "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", 1916, Common::EN_ANY, Common::kPlatformAtariST },
{ "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown },
+ { "839a658f7d22de00787ebc945348cdb6", "dog", "", "", 19681, Common::DE_DEU, Common::kPlatformWindows },
{ "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "84e3c23a49ded8a6f9197735c8eb3de7", "PuttTime", "HE 85", "", -1, Common::DE_DEU, Common::kPlatformWindows },
{ "8539c0ff89868e55a08e652ac44daaae", "water", "HE 98.5", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
@@ -330,6 +345,7 @@ static const MD5Table md5table[] = {
{ "86c9902b7bec1a17926d4dae85beaa45", "airport", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "870d1e3c86bc50846d808d14a36b4e08", "monkey", "VGA", "VGA", -1, Common::ES_ESP, Common::kPlatformAmiga },
{ "8776caed014c321272af407c1502a2df", "monkey", "CD", "", 8955, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "87df3e0074624040407764b7c5e710b9", "pajama", "", "Demo", 18354, Common::NL_NLD, Common::kPlatformWindows },
{ "87f6e8037b7cc996e13474b491a7a98e", "maniac", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformPC },
{ "8801fb4a1200b347f7a38523339526dd", "jungle", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "", "CD", -1, Common::ES_ESP, Common::kPlatformUnknown },
@@ -394,12 +410,14 @@ static const MD5Table md5table[] = {
{ "a0a7dea72003933b8b3f8b99b9f7ddeb", "loom", "No Adlib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST },
{ "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown },
{ "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows },
+ { "a2386da005672cbd5136f4f27a626c5f", "farm", "", "", 87061, Common::NL_NLD, Common::kPlatformWindows },
{ "a28135a7ade38cc0208b04507c46efd1", "spyfox", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "a2bb6aa0537402c1b3c2ea899ccef64b", "lost", "HE 99", "Demo", 15540, Common::EN_ANY, Common::kPlatformWindows },
{ "a3036878840720fbefa41e6965fa4a0a", "samnmax", "", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC },
{ "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a570381b028972d891052ee1e51dc011", "maniac", "V2", "V2", -1, Common::EN_ANY, Common::kPlatformAtariST },
+ { "a5c5388da9bf0e6662fdca8813a79d13", "farm", "", "", 86962, Common::EN_ANY, Common::kPlatformWindows },
{ "a654fb60c3b67d6317a7894ffd9f25c5", "pajama3", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "a85856675429fe88051744f755b72f93", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
@@ -429,10 +447,13 @@ static const MD5Table md5table[] = {
{ "b886b0a5d909c7158a914e1d7c1c6c65", "loom", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformPC },
{ "b8955d7d23b4972229060d1592489fef", "freddicove", "HE 100", "", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "b9ba19ce376efc69be78ef3baef8d2b9", "monkey", "CD", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "b9bb68c5d2c9b6e2d9c513a29a754a57", "puttmoon", "", "", 7828, Common::EN_ANY, Common::kPlatformPC },
{ "ba888e6831517597859e91aa173f945c", "spyfox", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown },
+ { "bab0fb81dcb12b8930c5d850b8f2a7de", "balloon", "HE 80", "", 12800, Common::DE_DEU, Common::kPlatformWindows },
{ "bbadf7309c4a2c2763e4bbba3c3be634", "freddi3", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown },
{ "bc4700bc0e12879f6d25d14d6be6cfdd", "spyfox2", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "bd126753de619a495f9f22adc951c8d5", "monkey2", "", "", -1, Common::IT_ITA, Common::kPlatformPC },
+ { "bd5fd7835335dfce03064d5f77b7f0ae", "dog", "", "", 19681, Common::NL_NLD, Common::kPlatformWindows },
{ "be2abe172f58db170de3a037daa1dd27", "puttputt", "HE 61", "", -1, Common::JA_JPN, Common::kPlatform3DO },
{ "be39a5d4db60e8aa736b9086778cb45c", "spyozon", "", "", -1, Common::EN_GRB, Common::kPlatformWindows },
{ "be83e882b44f2767bc08d4f766ebc347", "maniac", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAtariST },
@@ -441,6 +462,7 @@ static const MD5Table md5table[] = {
{ "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", -1, Common::NL_NLD, Common::kPlatformWindows },
{ "c0d5c89550381ac433624fedad5e1100", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine },
{ "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD },
+ { "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 100", "", -1, Common::EN_ANY, Common::kPlatformWii },
{ "c24c490373aeb48fbd54caa8e7ae376d", "loom", "No Adlib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST },
{ "c25755b08a8d0d47695e05f1e2111bfc", "freddi4", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "c30ef068add4277104243c31ce46c12b", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformAmiga },
@@ -546,6 +568,7 @@ static const MD5Table md5table[] = {
{ "ed361270102e355afe5236954216aba2", "lost", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "ede149fda3edfc1dbd7347e0737cb583", "tentacle", "", "CD", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "edfdb24a499d92c59f824c52987c0eec", "atlantis", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC },
+ { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO },
{ "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "ef347474f3c7be3b29584eaa133cca05", "samnmax", "", "Floppy", -1, Common::FR_FRA, Common::kPlatformPC },
{ "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 61", "", -1, Common::HB_ISR, Common::kPlatformPC },
@@ -566,6 +589,7 @@ static const MD5Table md5table[] = {
{ "f8be685007a8b425ba2a455da732f59f", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
{ "fa127d7c4bb47d05bb1c33ddcaa9f767", "loom", "EGA", "EGA", 5748, Common::DE_DEU, Common::kPlatformPC },
{ "fa30c4a7a806629626269b6dcab59a15", "BluesBirthday", "HE CUP", "Preview", 7819264, Common::UNK_LANG, Common::kPlatformUnknown },
+ { "fa84cb1018103a4ee4e5fa8041c1d0d1", "freddi4", "", "Demo", 13609, Common::DE_DEU, Common::kPlatformWindows },
{ "fb66aa42de21675116346213f176a366", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformAmiga },
{ "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown },
{ "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 2f0593dca8..a10af41145 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -109,7 +109,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_language(dr.language),
_debugger(0),
_currentScript(0xFF), // Let debug() work on init stage
- _pauseDialog(0), _mainMenuDialog(0), _versionDialog(0) {
+ _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) {
if (_game.platform == Common::kPlatformNES) {
_gdi = new GdiNES(this);
@@ -143,9 +143,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_objs = NULL;
_sound = NULL;
memset(&vm, 0, sizeof(vm));
- _quit = false;
_pauseDialog = NULL;
- _mainMenuDialog = NULL;
+ _scummMenuDialog = NULL;
_versionDialog = NULL;
_fastMode = 0;
_actors = NULL;
@@ -561,7 +560,7 @@ ScummEngine::~ScummEngine() {
delete _2byteFontPtr;
delete _charset;
delete _pauseDialog;
- delete _mainMenuDialog;
+ delete _scummMenuDialog;
delete _versionDialog;
delete _fileHandle;
@@ -815,7 +814,6 @@ ScummEngine_vCUPhe::ScummEngine_vCUPhe(OSystem *syst, const DetectorResult &dr)
_syst = syst;
_game = dr.game;
_filenamePattern = dr.fp,
- _quit = false;
_cupPlayer = new CUP_Player(syst, this, _mixer);
}
@@ -845,14 +843,13 @@ void ScummEngine_vCUPhe::parseEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
+#if 0
switch (event.type) {
- case Common::EVENT_QUIT:
- _quit = true;
- break;
default:
break;
}
+#endif
}
}
@@ -916,20 +913,20 @@ int ScummEngine::init() {
// Add default file directories.
if (((_game.platform == Common::kPlatformAmiga) || (_game.platform == Common::kPlatformAtariST)) && (_game.version <= 4)) {
// This is for the Amiga version of Indy3/Loom/Maniac/Zak
- File::addDefaultDirectory(_gameDataPath + "ROOMS/");
- File::addDefaultDirectory(_gameDataPath + "rooms/");
+ File::addDefaultDirectory(_gameDataDir.getChild("ROOMS"));
+ File::addDefaultDirectory(_gameDataDir.getChild("rooms"));
}
if ((_game.platform == Common::kPlatformMacintosh) && (_game.version == 3)) {
// This is for the Mac version of Indy3/Loom
- File::addDefaultDirectory(_gameDataPath + "Rooms 1/");
- File::addDefaultDirectory(_gameDataPath + "Rooms 2/");
- File::addDefaultDirectory(_gameDataPath + "Rooms 3/");
+ File::addDefaultDirectory(_gameDataDir.getChild("Rooms 1"));
+ File::addDefaultDirectory(_gameDataDir.getChild("Rooms 2"));
+ File::addDefaultDirectory(_gameDataDir.getChild("Rooms 3"));
}
#ifdef ENABLE_SCUMM_7_8
#ifdef MACOSX
- if (_game.version == 8 && !memcmp(_gameDataPath.c_str(), "/Volumes/MONKEY3_", 17)) {
+ if (_game.version == 8 && !memcmp(_gameDataDir.getPath().c_str(), "/Volumes/MONKEY3_", 17)) {
// Special case for COMI on Mac OS X. The mount points on OS X depend
// on the volume name. Hence if playing from CD, we'd get a problem.
// So if loading of a resource file fails, we fall back to the (fixed)
@@ -946,16 +943,16 @@ int ScummEngine::init() {
#endif
if (_game.version == 8) {
// This is for COMI
- File::addDefaultDirectory(_gameDataPath + "RESOURCE/");
- File::addDefaultDirectory(_gameDataPath + "resource/");
+ File::addDefaultDirectory(_gameDataDir.getChild("RESOURCE"));
+ File::addDefaultDirectory(_gameDataDir.getChild("resource"));
}
if (_game.version == 7) {
// This is for Full Throttle & The Dig
- File::addDefaultDirectory(_gameDataPath + "VIDEO/");
- File::addDefaultDirectory(_gameDataPath + "video/");
- File::addDefaultDirectory(_gameDataPath + "DATA/");
- File::addDefaultDirectory(_gameDataPath + "data/");
+ File::addDefaultDirectory(_gameDataDir.getChild("VIDEO"));
+ File::addDefaultDirectory(_gameDataDir.getChild("video"));
+ File::addDefaultDirectory(_gameDataDir.getChild("DATA"));
+ File::addDefaultDirectory(_gameDataDir.getChild("data"));
}
#endif
@@ -1108,7 +1105,7 @@ int ScummEngine::init() {
if (_game.version >= 5 && _game.version <= 7)
_sound->setupSound();
- updateSoundSettings();
+ syncSoundSettings();
return 0;
}
@@ -1310,6 +1307,8 @@ void ScummEngine::resetScumm() {
_actors[i] = new Actor_v2(this, i);
else if (_game.version == 3)
_actors[i] = new Actor_v3(this, i);
+ else if (_game.heversion != 0)
+ _actors[i] = new ActorHE(this, i);
else
_actors[i] = new Actor(this, i);
_actors[i]->initActor(-1);
@@ -1533,6 +1532,12 @@ void ScummEngine_v99he::resetScumm() {
byte *data = defineArray(129, kStringArray, 0, 0, 0, len);
memcpy(data, _filenamePattern.pattern, len);
}
+
+void ScummEngine_v100he::resetScumm() {
+ ScummEngine_v99he::resetScumm();
+
+ memset(_debugInputBuffer, 0, sizeof(_debugInputBuffer));
+}
#endif
void ScummEngine::setupMusic(int midi) {
@@ -1667,7 +1672,7 @@ void ScummEngine::setupMusic(int midi) {
}
}
-void ScummEngine::updateSoundSettings() {
+void ScummEngine::syncSoundSettings() {
// Sync the engine with the config manager
int soundVolumeMusic = ConfMan.getInt("music_volume");
@@ -1690,17 +1695,17 @@ void ScummEngine::updateSoundSettings() {
if (VAR_VOICE_MODE != 0xFF)
VAR(VAR_VOICE_MODE) = _voiceMode;
- _defaultTalkDelay = getTalkspeed();
+ _defaultTalkDelay = getTalkDelay();
if (VAR_CHARINC != 0xFF)
VAR(VAR_CHARINC) = _defaultTalkDelay;
}
-void ScummEngine::setTalkspeed(int talkspeed) {
- ConfMan.setInt("talkspeed", (talkspeed * 255 + 9 / 2) / 9);
+void ScummEngine::setTalkDelay(int talkdelay) {
+ ConfMan.setInt("talkspeed", ((9 - talkdelay) * 255 + 9 / 2) / 9);
}
-int ScummEngine::getTalkspeed() {
- return (ConfMan.getInt("talkspeed") * 9 + 255 / 2) / 255;
+int ScummEngine::getTalkDelay() {
+ return 9 - (ConfMan.getInt("talkspeed") * 9 + 255 / 2) / 255;
}
@@ -1721,7 +1726,7 @@ int ScummEngine::go() {
int diff = 0; // Duration of one loop iteration
- while (!_quit) {
+ while (!quit()) {
if (_debugger->isAttached())
_debugger->onFrame();
@@ -1754,7 +1759,7 @@ int ScummEngine::go() {
diff = _system->getMillis() - diff;
- if (_quit) {
+ if (quit()) {
// TODO: Maybe perform an autosave on exit?
}
}
@@ -1772,7 +1777,7 @@ void ScummEngine::waitForTimer(int msec_delay) {
start_time = _system->getMillis();
- while (!_quit) {
+ while (!quit()) {
_sound->updateCD(); // Loop CD Audio if needed
parseEvents();
_system->updateScreen();
@@ -1895,7 +1900,7 @@ load_game:
checkExecVerbs();
checkAndRunSentenceScript();
- if (_quit)
+ if (quit())
return;
// HACK: If a load was requested, immediately perform it. This avoids
@@ -2011,7 +2016,6 @@ void ScummEngine::scummLoop_handleSaveLoad() {
if (_saveLoadFlag) {
bool success;
const char *errMsg = 0;
- char filename[256];
if (_game.version == 8 && _saveTemporaryState)
VAR(VAR_GAME_LOADED) = 0;
@@ -2032,13 +2036,13 @@ void ScummEngine::scummLoop_handleSaveLoad() {
VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : 203;
}
- makeSavegameName(filename, _saveLoadSlot, _saveTemporaryState);
+ Common::String filename = makeSavegameName(_saveLoadSlot, _saveTemporaryState);
if (!success) {
- displayMessage(0, errMsg, filename);
+ displayMessage(0, errMsg, filename.c_str());
} else if (_saveLoadFlag == 1 && _saveLoadSlot != 0 && !_saveTemporaryState) {
// Display "Save successful" message, except for auto saves
char buf[256];
- snprintf(buf, sizeof(buf), "Successfully saved game state in file:\n\n%s", filename);
+ snprintf(buf, sizeof(buf), "Successfully saved game state in file:\n\n%s", filename.c_str());
GUI::TimedMessageDialog dialog(buf, 1500);
runDialog(dialog);
@@ -2160,10 +2164,6 @@ void ScummEngine::pauseGame() {
pauseDialog();
}
-void ScummEngine::shutDown() {
- _quit = true;
-}
-
void ScummEngine::restart() {
// TODO: Check this function - we should probably be reinitting a lot more stuff, and I suspect
// this leaks memory like a sieve
@@ -2305,18 +2305,18 @@ void ScummEngine::versionDialog() {
runDialog(*_versionDialog);
}
-void ScummEngine::mainMenuDialog() {
- if (!_mainMenuDialog)
- _mainMenuDialog = new MainMenuDialog(this);
- runDialog(*_mainMenuDialog);
- updateSoundSettings();
+void ScummEngine::scummMenuDialog() {
+ if (!_scummMenuDialog)
+ _scummMenuDialog = new ScummMenuDialog(this);
+ runDialog(*_scummMenuDialog);
+ syncSoundSettings();
}
void ScummEngine::confirmExitDialog() {
ConfirmDialog d(this, 6);
if (runDialog(d)) {
- _quit = true;
+ quitGame();
}
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 20824ffe74..ec733d32f4 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -46,7 +46,7 @@ namespace GUI {
using GUI::Dialog;
namespace Common {
class SeekableReadStream;
- class OutSaveFile;
+ class WriteStream;
}
namespace Scumm {
@@ -462,9 +462,9 @@ protected:
virtual void loadLanguageBundle() {}
void loadCJKFont();
void setupMusic(int midi);
- void updateSoundSettings();
- void setTalkspeed(int talkspeed);
- int getTalkspeed();
+ virtual void syncSoundSettings();
+ void setTalkDelay(int talkdelay);
+ int getTalkDelay();
// Scumm main loop & helper functions.
virtual void scummLoop(int delta);
@@ -496,22 +496,18 @@ protected:
public:
void pauseGame();
void restart();
- void shutDown();
-
- /** We keep running until this is set to true. */
- bool _quit;
protected:
Dialog *_pauseDialog;
Dialog *_versionDialog;
- Dialog *_mainMenuDialog;
+ Dialog *_scummMenuDialog;
virtual int runDialog(Dialog &dialog);
void confirmExitDialog();
void confirmRestartDialog();
void pauseDialog();
void versionDialog();
- void mainMenuDialog();
+ void scummMenuDialog();
char displayMessage(const char *altButton, const char *message, ...);
@@ -560,7 +556,7 @@ protected:
public:
int _numLocalScripts, _numImages, _numRooms, _numScripts, _numSounds; // Used by HE games
int _numCostumes; // FIXME - should be protected, used by Actor::remapActorPalette
- int _numCharsets; // FIXME - should be protected, used by CharsetRenderer
+ int32 _numCharsets; // FIXME - should be protected, used by CharsetRenderer
BaseCostumeLoader *_costumeLoader;
BaseCostumeRenderer *_costumeRenderer;
@@ -618,11 +614,16 @@ protected:
void saveLoadResource(Serializer *ser, int type, int index); // "Obsolete"
void saveResource(Serializer *ser, int type, int index);
void loadResource(Serializer *ser, int type, int index);
- void makeSavegameName(char *out, int slot, bool temporary);
+
+ Common::String makeSavegameName(int slot, bool temporary) const {
+ return makeSavegameName(_targetName, slot, temporary);
+ }
int getKeyState(int key);
public:
+ static Common::String makeSavegameName(const Common::String &target, int slot, bool temporary);
+
bool getSavegameName(int slot, Common::String &desc);
void listSavegames(bool *marks, int num);
@@ -631,14 +632,19 @@ public:
// thumbnail + info stuff
public:
- Graphics::Surface *loadThumbnailFromSlot(int slot);
- bool loadInfosFromSlot(int slot, InfoStuff *stuff);
+ Graphics::Surface *loadThumbnailFromSlot(int slot) {
+ return loadThumbnailFromSlot(_targetName.c_str(), slot);
+ }
+ static Graphics::Surface *loadThumbnailFromSlot(const char *target, int slot);
+
+ bool loadInfosFromSlot(int slot, InfoStuff *stuff) {
+ return loadInfosFromSlot(_targetName.c_str(), slot, stuff);
+ }
+ static bool loadInfosFromSlot(const char *target, int slot, InfoStuff *stuff);
protected:
- Graphics::Surface *loadThumbnail(Common::SeekableReadStream *file);
- bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff);
- void saveThumbnail(Common::OutSaveFile *file);
- void saveInfos(Common::OutSaveFile* file);
+ void saveInfos(Common::WriteStream* file);
+ static bool loadInfos(Common::SeekableReadStream *file, InfoStuff *stuff);
int32 _engineStartTime;
int32 _pauseStartTime;
@@ -673,7 +679,7 @@ protected:
void executeScript();
void updateScriptPtr();
virtual void runInventoryScript(int i);
- void inventoryScript();
+ void inventoryScriptIndy3Mac();
void checkAndRunSentenceScript();
void runExitScript();
void runEntryScript();
@@ -912,7 +918,7 @@ public:
// Generic costume code
bool isCostumeInUse(int i) const;
- Common::Rect _actorClipOverride;
+ Common::Rect _actorClipOverride; // HE specific
protected:
/* Should be in Graphics class? */
diff --git a/engines/scumm/smush/channel.h b/engines/scumm/smush/channel.h
index 52fec22e0e..1e023e08ff 100644
--- a/engines/scumm/smush/channel.h
+++ b/engines/scumm/smush/channel.h
@@ -28,10 +28,11 @@
#include "common/util.h"
-namespace Scumm {
+namespace Common {
+ class SeekableReadStream;
+}
-class Chunk;
-class ContChunk;
+namespace Scumm {
class SmushChannel {
protected:
@@ -55,7 +56,7 @@ protected:
public:
SmushChannel(int32 track);
virtual ~SmushChannel();
- virtual bool appendData(Chunk &b, int32 size) = 0;
+ virtual bool appendData(Common::SeekableReadStream &b, int32 size) = 0;
virtual bool setParameters(int32, int32, int32, int32, int32) = 0;
virtual bool checkParameters(int32, int32, int32, int32, int32) = 0;
virtual bool isTerminated() const = 0;
@@ -83,7 +84,7 @@ public:
bool isTerminated() const;
bool setParameters(int32 duration, int32 flags, int32 vol1, int32 vol2, int32 index);
bool checkParameters(int32 index, int32 duration, int32 flags, int32 vol1, int32 vol2);
- bool appendData(Chunk &b, int32 size);
+ bool appendData(Common::SeekableReadStream &b, int32 size);
byte *getSoundData();
int32 getRate() { return 22050; }
bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) {
@@ -105,7 +106,7 @@ private:
protected:
void decode();
- bool handleMap(Chunk &c);
+ bool handleMap(byte *data);
bool handleSubTags(int32 &offset);
public:
@@ -113,7 +114,7 @@ public:
bool isTerminated() const;
bool setParameters(int32 nbframes, int32 size, int32 track_flags, int32 unk1, int32);
bool checkParameters(int32 index, int32 nbframes, int32 size, int32 track_flags, int32 unk1);
- bool appendData(Chunk &b, int32 size);
+ bool appendData(Common::SeekableReadStream &b, int32 size);
byte *getSoundData();
int32 getRate() { return _rate; }
bool getParameters(bool &stereo, bool &is_16bit, int32 &vol, int32 &pan) {
diff --git a/engines/scumm/smush/chunk.cpp b/engines/scumm/smush/chunk.cpp
deleted file mode 100644
index 5e6f05b3e4..0000000000
--- a/engines/scumm/smush/chunk.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-
-#include "scumm/smush/chunk.h"
-#include "scumm/scumm.h"
-#include "scumm/file.h"
-
-#include "common/file.h"
-#include "common/str.h"
-#include "common/util.h"
-
-namespace Scumm {
-
-BaseChunk::BaseChunk() :
- _type(0),
- _size(0),
- _curPos(0),
- _name("") {
-}
-
-bool BaseChunk::eos() const {
- return _curPos >= _size;
-}
-
-uint32 BaseChunk::pos() const {
- return _curPos;
-}
-
-Chunk::type BaseChunk::getType() const {
- return _type;
-}
-
-uint32 BaseChunk::size() const {
- return _size;
-}
-
-void BaseChunk::seek(int32 delta, int dir) {
- switch (dir) {
- case SEEK_CUR:
- _curPos += delta;
- break;
- case SEEK_SET:
- if (delta < 0)
- error("invalid seek request");
- _curPos = (uint32)delta;
- break;
- case SEEK_END:
- if (delta > 0 || _size < (uint32)-delta)
- error("invalid seek request");
- _curPos = (uint32)(_size + delta);
- break;
- default:
- break;
- }
-
- if (_curPos > _size) {
- // It may happen that user misused our SAN compression tool
- // and ignored FLU index for videos which are used by INSANE.
- // This will lead to incorrect seek requests
- //
- // In fact it may happen only within INSANE, so do not even check for it
- warning("Looks like you compressed file %s in wrong way. It has FLU index which was not updated", _name.c_str());
- error("invalid seek request : %d > %d (delta == %d)", _curPos, _size, delta);
- }
-}
-
-FileChunk::FileChunk(BaseScummFile *data, int offset) {
- _data = data;
- _deleteData = false;
-
- _data->seek(offset, SEEK_SET);
- _type = _data->readUint32BE();
- _size = _data->readUint32BE();
- _offset = _data->pos();
- _curPos = 0;
-}
-
-FileChunk::FileChunk(const Common::String &name, int offset) {
- _data = new ScummFile();
- _deleteData = true;
- if (!g_scumm->openFile(*_data, name))
- error("FileChunk: Unable to open file %s", name.c_str());
-
- _data->seek(offset, SEEK_SET);
- _type = _data->readUint32BE();
- _size = _data->readUint32BE();
- _offset = _data->pos();
- _curPos = 0;
- _name = name;
-}
-
-FileChunk::~FileChunk() {
- if (_deleteData)
- delete _data;
-}
-
-Chunk *FileChunk::subBlock() {
- FileChunk *ptr = new FileChunk(_data, _offset + _curPos);
- skip(sizeof(Chunk::type) + sizeof(uint32) + ptr->size());
- return ptr;
-}
-
-void FileChunk::reseek() {
- _data->seek(_offset + _curPos, SEEK_SET);
-}
-
-uint32 FileChunk::read(void *buffer, uint32 dataSize) {
- if (dataSize <= 0 || (_curPos + dataSize) > _size)
- error("invalid buffer read request");
-
- dataSize = _data->read(buffer, dataSize);
- _curPos += dataSize;
-
- return dataSize;
-}
-
-MemoryChunk::MemoryChunk(byte *data) {
- if (data == 0)
- error("Chunk() called with NULL pointer");
-
- _type = (Chunk::type)READ_BE_UINT32(data);
- _size = READ_BE_UINT32(data + 4);
- _data = data + sizeof(Chunk::type) + sizeof(uint32);
- _curPos = 0;
-}
-
-Chunk *MemoryChunk::subBlock() {
- MemoryChunk *ptr = new MemoryChunk(_data + _curPos);
- skip(sizeof(Chunk::type) + sizeof(uint32) + ptr->size());
- return ptr;
-}
-
-void MemoryChunk::reseek() {
-}
-
-uint32 MemoryChunk::read(void *buffer, uint32 dataSize) {
- if (dataSize <= 0 || (_curPos + dataSize) > _size)
- error("invalid buffer read request");
-
- memcpy(buffer, _data + _curPos, dataSize);
- _curPos += dataSize;
- return dataSize;
-}
-
-} // End of namespace Scumm
diff --git a/engines/scumm/smush/imuse_channel.cpp b/engines/scumm/smush/imuse_channel.cpp
index 822f32a896..fd34a8f60d 100644
--- a/engines/scumm/smush/imuse_channel.cpp
+++ b/engines/scumm/smush/imuse_channel.cpp
@@ -29,7 +29,6 @@
#include "scumm/scumm.h" // For DEBUG_SMUSH
#include "scumm/util.h"
#include "scumm/smush/channel.h"
-#include "scumm/smush/chunk.h"
namespace Scumm {
@@ -60,10 +59,10 @@ bool ImuseChannel::checkParameters(int32 index, int32 nbframes, int32 size, int3
return true;
}
-bool ImuseChannel::appendData(Chunk &b, int32 size) {
+bool ImuseChannel::appendData(Common::SeekableReadStream &b, int32 size) {
if (_dataSize == -1) {
assert(size > 8);
- Chunk::type imus_type = b.readUint32BE();
+ uint32 imus_type = b.readUint32BE();
/*uint32 imus_size =*/ b.readUint32BE();
if (imus_type != MKID_BE('iMUS'))
error("Invalid Chunk for imuse_channel");
@@ -104,35 +103,45 @@ bool ImuseChannel::appendData(Chunk &b, int32 size) {
return true;
}
-bool ImuseChannel::handleMap(Chunk &map) {
- while (!map.eos()) {
- Chunk *sub = map.subBlock();
- switch (sub->getType()) {
+bool ImuseChannel::handleMap(byte *data) {
+ // Read the chunk size & skip over the chunk header
+ int32 size = READ_BE_UINT32(data + 4);
+ data += 8;
+
+ while (size > 0) {
+ uint32 subType = READ_BE_UINT32(data);
+ int32 subSize = READ_BE_UINT32(data + 4);
+ data += 8;
+ size -= 8;
+
+ switch (subType) {
case MKID_BE('FRMT'):
- if (sub->size() != 20)
+ if (subSize != 20)
error("invalid size for FRMT Chunk");
- /*uint32 imuse_start =*/ sub->readUint32BE();
- sub->skip(4);
- _bitsize = sub->readUint32BE();
- _rate = sub->readUint32BE();
- _channels = sub->readUint32BE();
+ //uint32 imuse_start = READ_BE_UINT32(data);
+ //uint32 unk = READ_BE_UINT32(data+4);
+ _bitsize = READ_BE_UINT32(data+8);
+ _rate = READ_BE_UINT32(data+12);
+ _channels = READ_BE_UINT32(data+16);
assert(_channels == 1 || _channels == 2);
break;
case MKID_BE('TEXT'):
// Ignore this
break;
case MKID_BE('REGN'):
- if (sub->size() != 8)
+ if (subSize != 8)
error("invalid size for REGN Chunk");
break;
case MKID_BE('STOP'):
- if (sub->size() != 4)
+ if (subSize != 4)
error("invalid size for STOP Chunk");
break;
default:
- error("Unknown iMUS subChunk found : %s, %d", tag2str(sub->getType()), sub->size());
+ error("Unknown iMUS subChunk found : %s, %d", tag2str(subType), subSize);
}
- delete sub;
+
+ data += subSize;
+ size -= subSize;
}
return true;
}
@@ -187,15 +196,14 @@ void ImuseChannel::decode() {
bool ImuseChannel::handleSubTags(int32 &offset) {
if (_tbufferSize - offset >= 8) {
- Chunk::type type = READ_BE_UINT32(_tbuffer + offset);
+ uint32 type = READ_BE_UINT32(_tbuffer + offset);
uint32 size = READ_BE_UINT32(_tbuffer + offset + 4);
uint32 available_size = _tbufferSize - offset;
switch (type) {
case MKID_BE('MAP '):
_inData = false;
if (available_size >= (size + 8)) {
- MemoryChunk c((byte *)_tbuffer + offset);
- handleMap(c);
+ handleMap((byte *)_tbuffer + offset);
}
break;
case MKID_BE('DATA'):
diff --git a/engines/scumm/smush/saud_channel.cpp b/engines/scumm/smush/saud_channel.cpp
index 2fe34efe29..a56afa8f44 100644
--- a/engines/scumm/smush/saud_channel.cpp
+++ b/engines/scumm/smush/saud_channel.cpp
@@ -25,10 +25,10 @@
#include "common/endian.h"
+#include "common/stream.h"
#include "scumm/util.h"
#include "scumm/smush/channel.h"
-#include "scumm/smush/chunk.h"
namespace Scumm {
@@ -45,7 +45,7 @@ bool SaudChannel::isTerminated() const {
bool SaudChannel::handleSubTags(int32 &offset) {
if (_tbufferSize - offset >= 8) {
- Chunk::type type = READ_BE_UINT32(_tbuffer + offset);
+ uint32 type = READ_BE_UINT32(_tbuffer + offset);
uint32 size = READ_BE_UINT32(_tbuffer + offset + 4);
uint32 available_size = _tbufferSize - offset;
@@ -53,9 +53,9 @@ bool SaudChannel::handleSubTags(int32 &offset) {
case MKID_BE('STRK'):
_inData = false;
if (available_size >= (size + 8)) {
- MemoryChunk c((byte *)_tbuffer + offset);
- if (c.size() != 14 && c.size() != 10) {
- error("STRK has an invalid size : %d", c.size());
+ int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4);
+ if (subSize != 14 && subSize != 10) {
+ error("STRK has an invalid size : %d", subSize);
}
} else
return false;
@@ -63,7 +63,9 @@ bool SaudChannel::handleSubTags(int32 &offset) {
case MKID_BE('SMRK'):
_inData = false;
if (available_size >= (size + 8)) {
- MemoryChunk c((byte *)_tbuffer + offset);
+ int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4);
+ if (subSize != 0)
+ error("SMRK has an invalid size : %d", subSize);
_markReached = true;
} else
return false;
@@ -71,9 +73,9 @@ bool SaudChannel::handleSubTags(int32 &offset) {
case MKID_BE('SHDR'):
_inData = false;
if (available_size >= (size + 8)) {
- MemoryChunk c((byte *)_tbuffer + offset);
- if (c.size() != 4)
- error("SHDR has an invalid size : %d", c.size());
+ int32 subSize = READ_BE_UINT32((byte *)_tbuffer + offset + 4);
+ if (subSize != 4)
+ error("SHDR has an invalid size : %d", subSize);
} else
return false;
break;
@@ -119,10 +121,10 @@ bool SaudChannel::checkParameters(int32 index, int32 nb, int32 flags, int32 volu
return true;
}
-bool SaudChannel::appendData(Chunk &b, int32 size) {
+bool SaudChannel::appendData(Common::SeekableReadStream &b, int32 size) {
if (_dataSize == -1) {
assert(size > 8);
- Chunk::type saud_type = b.readUint32BE();
+ uint32 saud_type = b.readUint32BE();
/*uint32 saud_size =*/ b.readUint32BE();
if (saud_type != MKID_BE('SAUD'))
error("Invalid Chunk for SaudChannel : %X", saud_type);
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 494357a90c..6b79b7e2c4 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -23,8 +23,6 @@
*
*/
-
-
#include "engines/engine.h"
#include "common/config-manager.h"
@@ -42,7 +40,6 @@
#include "scumm/sound.h"
#include "scumm/util.h"
#include "scumm/smush/channel.h"
-#include "scumm/smush/chunk.h"
#include "scumm/smush/codec37.h"
#include "scumm/smush/codec47.h"
#include "scumm/smush/smush_font.h"
@@ -55,10 +52,6 @@
#include "sound/vorbis.h"
#include "sound/mp3.h"
-#ifdef DUMP_SMUSH_FRAMES
-#include <png.h>
-#endif
-
#include "common/zlib.h"
namespace Scumm {
@@ -212,10 +205,6 @@ static StringResource *getStrings(ScummEngine *vm, const char *file, bool is_enc
void SmushPlayer::timerCallback() {
parseNextFrame();
-#ifdef _WIN32_WCE
- _inTimer = true;
- _inTimerCount++;
-#endif
}
SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {
@@ -252,11 +241,6 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {
_paused = false;
_pauseStartTime = 0;
_pauseTime = 0;
-#ifdef _WIN32_WCE
- _inTimer = false;
- _inTimerCount = 0;
- _inTimerCountRedraw = ConfMan.getInt("Smush_force_redraw");
-#endif
}
SmushPlayer::~SmushPlayer() {
@@ -328,16 +312,7 @@ void SmushPlayer::release() {
_codec47 = 0;
}
-void SmushPlayer::checkBlock(const Chunk &b, Chunk::type type_expected, uint32 min_size) {
- if (type_expected != b.getType()) {
- error("Chunk type is different from expected : %x != %x", b.getType(), type_expected);
- }
- if (min_size > b.size()) {
- error("Chunk size is inferior than minimum required size : %d < %d", b.size(), min_size);
- }
-}
-
-void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Chunk &b, int32 size) {
+void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frames, int32 flags, int32 vol, int32 pan, Common::SeekableReadStream &b, int32 size) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundBuffer(%d, %d)", track_id, index);
// if ((flags & 128) == 128) {
// return;
@@ -360,8 +335,7 @@ void SmushPlayer::handleSoundBuffer(int32 track_id, int32 index, int32 max_frame
c->appendData(b, size);
}
-void SmushPlayer::handleSoundFrame(Chunk &b) {
- checkBlock(b, MKID_BE('PSAD'));
+void SmushPlayer::handleSoundFrame(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleSoundFrame()");
int32 track_id = b.readUint16LE();
@@ -373,28 +347,28 @@ void SmushPlayer::handleSoundFrame(Chunk &b) {
if (index == 0) {
debugC(DEBUG_SMUSH, "track_id:%d, max_frames:%d, flags:%d, vol:%d, pan:%d", track_id, max_frames, flags, vol, pan);
}
- int32 size = b.size() - 10;
+ int32 size = subSize - 10;
handleSoundBuffer(track_id, index, max_frames, flags, vol, pan, b, size);
}
-void SmushPlayer::handleStore(Chunk &b) {
+void SmushPlayer::handleStore(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleStore()");
- checkBlock(b, MKID_BE('STOR'), 4);
+ assert(subSize >= 4);
_storeFrame = true;
}
-void SmushPlayer::handleFetch(Chunk &b) {
+void SmushPlayer::handleFetch(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleFetch()");
- checkBlock(b, MKID_BE('FTCH'), 6);
+ assert(subSize >= 6);
if (_frameBuffer != NULL) {
memcpy(_dst, _frameBuffer, _width * _height);
}
}
-void SmushPlayer::handleIACT(Chunk &b) {
- checkBlock(b, MKID_BE('IACT'), 8);
+void SmushPlayer::handleIACT(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::IACT()");
+ assert(subSize >= 8);
int code = b.readUint16LE();
int flags = b.readUint16LE();
@@ -415,7 +389,7 @@ void SmushPlayer::handleIACT(Chunk &b) {
int index = b.readUint16LE();
int nbframes = b.readUint16LE();
int32 size = b.readUint32LE();
- int32 bsize = b.size() - 18;
+ int32 bsize = subSize - 18;
if (_vm->_game.id != GID_CMI) {
int32 track = track_id;
@@ -519,7 +493,7 @@ void SmushPlayer::handleIACT(Chunk &b) {
}
}
-void SmushPlayer::handleTextResource(Chunk &b) {
+void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &b) {
int pos_x = b.readSint16LE();
int pos_y = b.readSint16LE();
int flags = b.readSint16LE();
@@ -531,10 +505,10 @@ void SmushPlayer::handleTextResource(Chunk &b) {
const char *str;
char *string = NULL, *string2 = NULL;
- if (b.getType() == MKID_BE('TEXT')) {
- string = (char *)malloc(b.size() - 16);
+ if (subType == MKID_BE('TEXT')) {
+ string = (char *)malloc(subSize - 16);
str = string;
- b.read(string, b.size() - 16);
+ b.read(string, subSize - 16);
} else {
int string_id = b.readUint16LE();
if (!_strings)
@@ -702,7 +676,7 @@ bool SmushPlayer::readString(const char *file) {
return false;
}
-void SmushPlayer::readPalette(byte *out, Chunk &in) {
+void SmushPlayer::readPalette(byte *out, Common::SeekableReadStream &in) {
in.read(out, 0x300);
}
@@ -711,11 +685,10 @@ static byte delta_color(byte org_color, int16 delta_color) {
return CLIP(t, 0, 255);
}
-void SmushPlayer::handleDeltaPalette(Chunk &b) {
- checkBlock(b, MKID_BE('XPAL'));
+void SmushPlayer::handleDeltaPalette(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleDeltaPalette()");
- if (b.size() == 0x300 * 3 + 4) {
+ if (subSize == 0x300 * 3 + 4) {
b.readUint16LE();
b.readUint16LE();
@@ -725,7 +698,7 @@ void SmushPlayer::handleDeltaPalette(Chunk &b) {
}
readPalette(_pal, b);
setDirtyColors(0, 255);
- } else if (b.size() == 6) {
+ } else if (subSize == 6) {
b.readUint16LE();
b.readUint16LE();
@@ -740,9 +713,9 @@ void SmushPlayer::handleDeltaPalette(Chunk &b) {
}
}
-void SmushPlayer::handleNewPalette(Chunk &b) {
- checkBlock(b, MKID_BE('NPAL'), 0x300);
+void SmushPlayer::handleNewPalette(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleNewPalette()");
+ assert(subSize >= 0x300);
if (_skipPalette)
return;
@@ -805,21 +778,20 @@ void SmushPlayer::decodeFrameObject(int codec, const uint8 *src, int left, int t
}
#ifdef USE_ZLIB
-void SmushPlayer::handleZlibFrameObject(Chunk &b) {
+void SmushPlayer::handleZlibFrameObject(int32 subSize, Common::SeekableReadStream &b) {
if (_skipNext) {
_skipNext = false;
return;
}
- int32 chunkSize = b.size();
+ int32 chunkSize = subSize;
byte *chunkBuffer = (byte *)malloc(chunkSize);
assert(chunkBuffer);
b.read(chunkBuffer, chunkSize);
unsigned long decompressedSize = READ_BE_UINT32(chunkBuffer);
byte *fobjBuffer = (byte *)malloc(decompressedSize);
- int result = Common::uncompress(fobjBuffer, &decompressedSize, chunkBuffer + 4, chunkSize - 4);
- if (result != Common::ZLIB_OK)
+ if (!Common::uncompress(fobjBuffer, &decompressedSize, chunkBuffer + 4, chunkSize - 4))
error("SmushPlayer::handleZlibFrameObject() Zlib uncompress error");
free(chunkBuffer);
@@ -836,8 +808,8 @@ void SmushPlayer::handleZlibFrameObject(Chunk &b) {
}
#endif
-void SmushPlayer::handleFrameObject(Chunk &b) {
- checkBlock(b, MKID_BE('FOBJ'), 14);
+void SmushPlayer::handleFrameObject(int32 subSize, Common::SeekableReadStream &b) {
+ assert(subSize >= 14);
if (_skipNext) {
_skipNext = false;
return;
@@ -852,7 +824,7 @@ void SmushPlayer::handleFrameObject(Chunk &b) {
b.readUint16LE();
b.readUint16LE();
- int32 chunk_size = b.size() - 14;
+ int32 chunk_size = subSize - 14;
byte *chunk_buffer = (byte *)malloc(chunk_size);
assert(chunk_buffer);
b.read(chunk_buffer, chunk_size);
@@ -862,8 +834,7 @@ void SmushPlayer::handleFrameObject(Chunk &b) {
free(chunk_buffer);
}
-void SmushPlayer::handleFrame(Chunk &b) {
- checkBlock(b, MKID_BE('FRME'));
+void SmushPlayer::handleFrame(int32 frameSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleFrame(%d)", _frame);
_skipNext = false;
@@ -871,54 +842,57 @@ void SmushPlayer::handleFrame(Chunk &b) {
_vm->_insane->procPreRendering();
}
- while (!b.eos()) {
- Chunk *sub = b.subBlock();
- switch (sub->getType()) {
+ while (frameSize > 0) {
+ const uint32 subType = b.readUint32BE();
+ const int32 subSize = b.readUint32BE();
+ const int32 subOffset = b.pos();
+ switch (subType) {
case MKID_BE('NPAL'):
- handleNewPalette(*sub);
+ handleNewPalette(subSize, b);
break;
case MKID_BE('FOBJ'):
- handleFrameObject(*sub);
+ handleFrameObject(subSize, b);
break;
#ifdef USE_ZLIB
case MKID_BE('ZFOB'):
- handleZlibFrameObject(*sub);
+ handleZlibFrameObject(subSize, b);
break;
#endif
case MKID_BE('PSAD'):
if (!_compressedFileMode)
- handleSoundFrame(*sub);
+ handleSoundFrame(subSize, b);
break;
case MKID_BE('TRES'):
- handleTextResource(*sub);
+ handleTextResource(subType, subSize, b);
break;
case MKID_BE('XPAL'):
- handleDeltaPalette(*sub);
+ handleDeltaPalette(subSize, b);
break;
case MKID_BE('IACT'):
- handleIACT(*sub);
+ handleIACT(subSize, b);
break;
case MKID_BE('STOR'):
- handleStore(*sub);
+ handleStore(subSize, b);
break;
case MKID_BE('FTCH'):
- handleFetch(*sub);
+ handleFetch(subSize, b);
break;
case MKID_BE('SKIP'):
- _vm->_insane->procSKIP(*sub);
+ _vm->_insane->procSKIP(subSize, b);
break;
case MKID_BE('TEXT'):
- handleTextResource(*sub);
+ handleTextResource(subType, subSize, b);
break;
default:
- error("Unknown frame subChunk found : %s, %d", tag2str(sub->getType()), sub->size());
+ error("Unknown frame subChunk found : %s, %d", tag2str(subType), subSize);
}
- b.reseek();
- if (sub->size() & 1)
+ frameSize -= subSize + 8;
+ b.seek(subOffset + subSize, SEEK_SET);
+ if (subSize & 1) {
b.skip(1);
-
- delete sub;
+ frameSize--;
+ }
}
if (_insanity) {
@@ -926,23 +900,16 @@ void SmushPlayer::handleFrame(Chunk &b) {
}
if (_width != 0 && _height != 0) {
-#ifdef _WIN32_WCE
- if (!_inTimer || _inTimerCount == _inTimerCountRedraw) {
- updateScreen();
- _inTimerCount = 0;
- }
-#else
updateScreen();
-#endif
}
_smixer->handleFrame();
_frame++;
}
-void SmushPlayer::handleAnimHeader(Chunk &b) {
- checkBlock(b, MKID_BE('AHDR'), 0x300 + 6);
+void SmushPlayer::handleAnimHeader(int32 subSize, Common::SeekableReadStream &b) {
debugC(DEBUG_SMUSH, "SmushPlayer::handleAnimHeader()");
+ assert(subSize >= 0x300 + 6);
/* _version = */ b.readUint16LE();
_nbframes = b.readUint16LE();
@@ -1004,7 +971,6 @@ SmushFont *SmushPlayer::getFont(int font) {
}
void SmushPlayer::parseNextFrame() {
- Chunk *sub;
if (_seekPos >= 0) {
if (_smixer)
@@ -1012,15 +978,23 @@ void SmushPlayer::parseNextFrame() {
if (_seekFile.size() > 0) {
delete _base;
- _base = new FileChunk(_seekFile);
+
+ ScummFile *tmp = new ScummFile();
+ if (!g_scumm->openFile(*tmp, _seekFile))
+ error("SmushPlayer: Unable to open file %s", _seekFile.c_str());
+ _base = tmp;
+ _base->readUint32BE();
+ _base->readUint32BE();
if (_seekPos > 0) {
assert(_seekPos > 8);
// In this case we need to get palette and number of frames
- sub = _base->subBlock();
- checkBlock(*sub, MKID_BE('AHDR'));
- handleAnimHeader(*sub);
- delete sub;
+ const uint32 subType = _base->readUint32BE();
+ const int32 subSize = _base->readUint32BE();
+ const int32 subOffset = _base->pos();
+ assert(subType == MKID_BE('AHDR'));
+ handleAnimHeader(subSize, *_base);
+ _base->seek(subOffset + subSize, SEEK_SET);
_middleAudio = true;
_seekPos -= 8;
@@ -1034,7 +1008,7 @@ void SmushPlayer::parseNextFrame() {
_skipPalette = true;
}
- _base->seek(_seekPos, SEEK_SET);
+ _base->seek(_seekPos + 8, SEEK_SET);
_frame = _seekFrame;
_startFrame = _frame;
_startTime = _vm->_system->getMillis();
@@ -1049,21 +1023,22 @@ void SmushPlayer::parseNextFrame() {
return;
}
- sub = _base->subBlock();
+ const uint32 subType = _base->readUint32BE();
+ const int32 subSize = _base->readUint32BE();
+ const int32 subOffset = _base->pos();
- switch (sub->getType()) {
+ switch (subType) {
case MKID_BE('AHDR'): // FT INSANE may seek file to the beginning
- handleAnimHeader(*sub);
+ handleAnimHeader(subSize, *_base);
break;
case MKID_BE('FRME'):
- handleFrame(*sub);
+ handleFrame(subSize, *_base);
break;
default:
- error("Unknown Chunk found at %x: %x, %d", _base->pos(), sub->getType(), sub->size());
+ error("Unknown Chunk found at %x: %x, %d", subOffset, subType, subSize);
}
- delete sub;
- _base->reseek();
+ _base->seek(subOffset + subSize, SEEK_SET);
if (_insanity)
_vm->_sound->processSound();
@@ -1098,57 +1073,6 @@ void SmushPlayer::warpMouse(int x, int y, int buttons) {
}
void SmushPlayer::updateScreen() {
-#ifdef DUMP_SMUSH_FRAMES
- char fileName[100];
- // change path below for dump png files
- sprintf(fileName, "/path/to/somethere/%s%04d.png", _vm->getBaseName(), _frame);
- FILE *file = fopen(fileName, "wb");
- if (file == NULL)
- error("can't open file for writing png");
-
- png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
- if (png_ptr == NULL) {
- fclose(file);
- error("can't write png header");
- }
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL) {
- fclose(file);
- error("can't create png info struct");
- }
- if (setjmp(png_ptr->jmpbuf)) {
- fclose(file);
- error("png jmpbuf error");
- }
-
- png_init_io(png_ptr, file);
-
- png_set_IHDR(png_ptr, info_ptr, _width, _height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
- png_colorp palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
- for (int i = 0; i != 256; ++i) {
- (palette + i)->red = _pal[i * 3 + 0];
- (palette + i)->green = _pal[i * 3 + 1];
- (palette + i)->blue = _pal[i * 3 + 2];
- }
-
- png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
-
- png_write_info(png_ptr, info_ptr);
- png_set_flush(png_ptr, 10);
-
- png_bytep row_pointers[480];
- for (int y = 0 ; y < _height ; y++)
- row_pointers[y] = (png_byte *) (_dst + y * _width);
- png_write_image(png_ptr, row_pointers);
- png_write_end(png_ptr, info_ptr);
- png_free(png_ptr, palette);
-
- fclose(file);
- png_destroy_write_struct(&png_ptr, &info_ptr);
-#endif
-
uint32 end_time, start_time = _vm->_system->getMillis();
_updateNeeded = true;
end_time = _vm->_system->getMillis();
@@ -1326,14 +1250,10 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
_vm->_system->updateScreen();
_updateNeeded = false;
}
-#ifdef _WIN32_WCE
- _inTimer = false;
- _inTimerCount = 0;
-#endif
}
if (_endOfFile)
break;
- if (_vm->_quit || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
+ if (_vm->quit() || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
_smixer->stop();
_vm->_mixer->stopHandle(_compressedFileSoundHandle);
_vm->_mixer->stopHandle(_IACTchannel);
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index 413a5895d3..2e2996009c 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -27,7 +27,6 @@
#define SCUMM_SMUSH_PLAYER_H
#include "common/util.h"
-#include "scumm/smush/chunk.h"
#include "scumm/sound.h"
namespace Scumm {
@@ -51,7 +50,7 @@ private:
StringResource *_strings;
Codec37Decoder *_codec37;
Codec47Decoder *_codec47;
- FileChunk *_base;
+ Common::SeekableReadStream *_base;
byte *_frameBuffer;
byte *_specialBuffer;
@@ -84,11 +83,6 @@ private:
bool _insanity;
bool _middleAudio;
bool _skipPalette;
-#ifdef _WIN32_WCE
- bool _inTimer;
- int16 _inTimerCount;
- int16 _inTimerCountRedraw;
-#endif
public:
SmushPlayer(ScummEngine_v7 *scumm);
@@ -126,22 +120,21 @@ private:
bool readString(const char *file);
void decodeFrameObject(int codec, const uint8 *src, int left, int top, int width, int height);
- void checkBlock(const Chunk &, Chunk::type, uint32 = 0);
- void handleAnimHeader(Chunk &);
- void handleFrame(Chunk &);
- void handleNewPalette(Chunk &);
+ void handleAnimHeader(int32 subSize, Common::SeekableReadStream &);
+ void handleFrame(int32 frameSize, Common::SeekableReadStream &);
+ void handleNewPalette(int32 subSize, Common::SeekableReadStream &);
#ifdef USE_ZLIB
- void handleZlibFrameObject(Chunk &b);
+ void handleZlibFrameObject(int32 subSize, Common::SeekableReadStream &b);
#endif
- void handleFrameObject(Chunk &);
- void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Chunk &, int32);
- void handleSoundFrame(Chunk &);
- void handleStore(Chunk &);
- void handleFetch(Chunk &);
- void handleIACT(Chunk &);
- void handleTextResource(Chunk &);
- void handleDeltaPalette(Chunk &);
- void readPalette(byte *, Chunk &);
+ void handleFrameObject(int32 subSize, Common::SeekableReadStream &);
+ void handleSoundBuffer(int32, int32, int32, int32, int32, int32, Common::SeekableReadStream &, int32);
+ void handleSoundFrame(int32 subSize, Common::SeekableReadStream &);
+ void handleStore(int32 subSize, Common::SeekableReadStream &);
+ void handleFetch(int32 subSize, Common::SeekableReadStream &);
+ void handleIACT(int32 subSize, Common::SeekableReadStream &);
+ void handleTextResource(uint32 subType, int32 subSize, Common::SeekableReadStream &);
+ void handleDeltaPalette(int32 subSize, Common::SeekableReadStream &);
+ void readPalette(byte *, Common::SeekableReadStream &);
void timerCallback();
};
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index f039e2ca23..700632e4b3 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -279,7 +279,7 @@ bool ScummEngine::handleNextCharsetCode(Actor *a, int *code) {
}
c = *buffer++;
- if (c == _newLineCharacter) {
+ if (_newLineCharacter != 0 && c == _newLineCharacter) {
c = 13;
break;
}
diff --git a/engines/scumm/thumbnail.cpp b/engines/scumm/thumbnail.cpp
deleted file mode 100644
index 40f1ee48e5..0000000000
--- a/engines/scumm/thumbnail.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed file the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-
-#include "common/system.h"
-#include "common/savefile.h"
-#include "graphics/scaler.h"
-#include "scumm/scumm.h"
-
-namespace Scumm {
-
-#define THMB_VERSION 1
-
-struct ThumbnailHeader {
- uint32 type;
- uint32 size;
- byte version;
- uint16 width, height;
- byte bpp;
-};
-
-#define ThumbnailHeaderSize (4+4+1+2+2+1)
-
-inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
- r = (((color >> 11) & 0x1F) << 3);
- g = (((color >> 5) & 0x3F) << 2);
- b = ((color&0x1F) << 3);
-}
-
-Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) {
- ThumbnailHeader header;
-
- header.type = file->readUint32BE();
- // We also accept the bad 'BMHT' header here, for the sake of compatibility
- // with some older savegames which were written incorrectly due to a bug in
- // ScummVM which wrote the thumb header type incorrectly on LE systems.
- if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT'))
- return 0;
-
- header.size = file->readUint32BE();
- header.version = file->readByte();
-
- if (header.version > THMB_VERSION) {
- file->skip(header.size - 9);
- warning("Loading a newer thumbnail version");
- return 0;
- }
-
- header.width = file->readUint16BE();
- header.height = file->readUint16BE();
- header.bpp = file->readByte();
-
- // TODO: support other bpp values than 2
- if (header.bpp != 2) {
- file->skip(header.size - 14);
- return 0;
- }
-
- Graphics::Surface *thumb = new Graphics::Surface();
- thumb->create(header.width, header.height, sizeof(OverlayColor));
-
- OverlayColor* pixels = (OverlayColor *)thumb->pixels;
-
- for (int y = 0; y < thumb->h; ++y) {
- for (int x = 0; x < thumb->w; ++x) {
- uint8 r, g, b;
- colorToRGB(file->readUint16BE(), r, g, b);
-
- // converting to current OSystem Color
- *pixels++ = _system->RGBToColor(r, g, b);
- }
- }
-
- return thumb;
-}
-
-void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
- Graphics::Surface thumb;
-
-#if !defined(__DS__)
- if (!createThumbnailFromScreen(&thumb))
-#endif
- thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));
-
- ThumbnailHeader header;
- header.type = MKID_BE('THMB');
- header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
- header.version = THMB_VERSION;
- header.width = thumb.w;
- header.height = thumb.h;
- header.bpp = thumb.bytesPerPixel;
-
- file->writeUint32BE(header.type);
- file->writeUint32BE(header.size);
- file->writeByte(header.version);
- file->writeUint16BE(header.width);
- file->writeUint16BE(header.height);
- file->writeByte(header.bpp);
-
- // TODO: for later this shouldn't be casted to uint16...
- uint16* pixels = (uint16 *)thumb.pixels;
- for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
- file->writeUint16BE(*pixels);
-
- thumb.free();
-}
-
-} // end of namespace Scumm
diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp
index 53169402e1..8699c893e4 100644
--- a/engines/sky/control.cpp
+++ b/engines/sky/control.cpp
@@ -238,13 +238,17 @@ void Control::removePanel(void) {
free(_sprites.slide2); free(_sprites.slode);
free(_sprites.slode2); free(_sprites.musicBodge);
delete _controlPanel; delete _exitButton;
- delete _slide; delete _slide2;
- delete _slode; delete _restorePanButton;
+ delete _slide; delete _slide2;
+ delete _slode; delete _restorePanButton;
+ delete _savePanel; delete _saveButton;
+ delete _downFastButton; delete _downSlowButton;
+ delete _upFastButton; delete _upSlowButton;
+ delete _quitButton; delete _autoSaveButton;
delete _savePanButton; delete _dosPanButton;
delete _restartPanButton; delete _fxPanButton;
delete _musicPanButton; delete _bodge;
- delete _yesNo; delete _text;
- delete _statusBar; delete _restoreButton;
+ delete _yesNo; delete _text;
+ delete _statusBar; delete _restoreButton;
if (_textSprite) {
free(_textSprite);
@@ -492,7 +496,7 @@ void Control::doControlPanel(void) {
_curButtonText = 0;
uint16 clickRes = 0;
- while (!quitPanel && !SkyEngine::_systemVars.quitGame) {
+ while (!quitPanel && !g_engine->quit()) {
_text->drawToScreen(WITH_MASK);
_system->updateScreen();
_mouseClicked = false;
@@ -524,7 +528,7 @@ void Control::doControlPanel(void) {
}
memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
_system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
- if (!SkyEngine::_systemVars.quitGame)
+ if (!g_engine->quit())
_system->updateScreen();
_skyScreen->forceRefresh();
_skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
@@ -603,7 +607,7 @@ uint16 Control::handleClick(ConResource *pButton) {
case QUIT_TO_DOS:
animClick(pButton);
if (getYesNo(quitDos))
- SkyEngine::_systemVars.quitGame = true;
+ g_engine->quitGame();
return 0;
default:
error("Control::handleClick: unknown routine: %X",pButton->_onClick);
@@ -875,7 +879,7 @@ uint16 Control::saveRestorePanel(bool allowSave) {
bool refreshNames = true;
bool refreshAll = true;
uint16 clickRes = 0;
- while (!quitPanel && !SkyEngine::_systemVars.quitGame) {
+ while (!quitPanel && !g_engine->quit()) {
clickRes = 0;
if (refreshNames || refreshAll) {
if (refreshAll) {
@@ -986,7 +990,7 @@ void Control::handleKeyPress(Common::KeyState kbd, Common::String &textBuf) {
if (kbd.keycode == Common::KEYCODE_BACKSPACE) { // backspace
if (textBuf.size() > 0)
textBuf.deleteLastChar();
- } else {
+ } else if (kbd.ascii) {
// Cannot enter text wider than the save/load panel
if (_enteredTextWidth >= PAN_LINE_WIDTH - 10)
return;
@@ -1546,9 +1550,6 @@ void Control::delay(unsigned int amount) {
case Common::EVENT_WHEELDOWN:
_mouseWheel = 1;
break;
- case Common::EVENT_QUIT:
- SkyEngine::_systemVars.quitGame = true;
- break;
default:
break;
}
diff --git a/engines/sky/intro.cpp b/engines/sky/intro.cpp
index 024360561c..86e26309c9 100644
--- a/engines/sky/intro.cpp
+++ b/engines/sky/intro.cpp
@@ -636,14 +636,10 @@ Intro::Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *t
_textBuf = (uint8*)malloc(10000);
_saveBuf = (uint8*)malloc(10000);
_bgBuf = NULL;
- _quitProg = false;
_relDelay = 0;
}
Intro::~Intro(void) {
-
- _mixer->stopAll();
- _skyScreen->stopSequence();
if (_textBuf)
free(_textBuf);
if (_saveBuf)
@@ -912,8 +908,7 @@ bool Intro::escDelay(uint32 msecs) {
if (event.type == Common::EVENT_KEYDOWN) {
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
return false;
- } else if (event.type == Common::EVENT_QUIT) {
- _quitProg = true;
+ } else if (event.type == Common::EVENT_QUIT || event.type == Common::EVENT_RTL) {
return false;
}
}
diff --git a/engines/sky/intro.h b/engines/sky/intro.h
index 4a54fb8dd3..796bcf7e36 100644
--- a/engines/sky/intro.h
+++ b/engines/sky/intro.h
@@ -43,7 +43,6 @@ public:
Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *text, Audio::Mixer *mixer, OSystem *system);
~Intro(void);
bool doIntro(bool floppyIntro);
- bool _quitProg;
private:
static uint16 _mainIntroSeq[];
static uint16 _floppyIntroSeq[];
diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp
index ed7e419f64..9f13bf9bee 100644
--- a/engines/sky/logic.cpp
+++ b/engines/sky/logic.cpp
@@ -1774,6 +1774,7 @@ bool Logic::fnChooser(uint32 a, uint32 b, uint32 c) {
uint32 size = ((dataFileHeader *)data)->s_height * ((dataFileHeader *)data)->s_width;
uint32 index = 0;
uint32 width = ((dataFileHeader *)data)->s_width;
+ uint32 height = ((dataFileHeader *)data)->s_height;
data += sizeof(dataFileHeader);
@@ -1794,7 +1795,7 @@ bool Logic::fnChooser(uint32 a, uint32 b, uint32 c) {
textCompact->xcood = TOP_LEFT_X; // set coordinates
textCompact->ycood = ycood;
- ycood += 12;
+ ycood += height;
}
if (p == _scriptVariables + TEXT1)
@@ -2489,7 +2490,7 @@ bool Logic::fnFadeUp(uint32 a, uint32 b, uint32 c) {
}
bool Logic::fnQuitToDos(uint32 a, uint32 b, uint32 c) {
- SkyEngine::_systemVars.quitGame = true;
+ g_engine->quitGame();
return false;
}
diff --git a/engines/sky/mouse.cpp b/engines/sky/mouse.cpp
index b3be8b4f36..1fc9e47539 100644
--- a/engines/sky/mouse.cpp
+++ b/engines/sky/mouse.cpp
@@ -180,7 +180,6 @@ void Mouse::waitMouseNotPressed(int minDelay) {
while (mousePressed || _system->getMillis() < now + minDelay) {
if (eventMan->shouldQuit()) {
- SkyEngine::_systemVars.quitGame = true;
minDelay = 0;
mousePressed = false;
}
diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp
index d87ed06fef..0900ba5617 100644
--- a/engines/sky/sky.cpp
+++ b/engines/sky/sky.cpp
@@ -110,9 +110,10 @@ public:
virtual const char *getName() const;
virtual const char *getCopyright() const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const FSList &fslist) const;
+ virtual GameList detectGames(const Common::FSList &fslist) const;
virtual PluginError createInstance(OSystem *syst, Engine **engine) const;
@@ -127,6 +128,13 @@ const char *SkyMetaEngine::getCopyright() const {
return "Beneath a Steel Sky (C) Revolution";
}
+bool SkyMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad);
+}
+
GameList SkyMetaEngine::getSupportedGames() const {
GameList games;
games.push_back(skySetting);
@@ -139,7 +147,7 @@ GameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
return GameDescriptor();
}
-GameList SkyMetaEngine::detectGames(const FSList &fslist) const {
+GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
GameList detectedGames;
bool hasSkyDsk = false;
bool hasSkyDnr = false;
@@ -147,7 +155,7 @@ GameList SkyMetaEngine::detectGames(const FSList &fslist) const {
int dataDiskSize = -1;
// Iterate over all files in the given directory
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (!file->isDirectory()) {
const char *fileName = file->getName().c_str();
@@ -257,7 +265,7 @@ namespace Sky {
void *SkyEngine::_itemList[300];
-SystemVars SkyEngine::_systemVars = {0, 0, 0, 0, 4316, 0, 0, false, false, false };
+SystemVars SkyEngine::_systemVars = {0, 0, 0, 0, 4316, 0, 0, false, false };
SkyEngine::SkyEngine(OSystem *syst)
: Engine(syst), _fastMode(0), _debugger(0) {
@@ -277,6 +285,8 @@ SkyEngine::~SkyEngine() {
delete _skyDisk;
delete _skyControl;
delete _skyCompact;
+ if (_skyIntro)
+ delete _skyIntro;
for (int i = 0; i < 300; i++)
if (_itemList[i])
@@ -288,7 +298,6 @@ GUI::Debugger *SkyEngine::getDebugger() {
}
void SkyEngine::initVirgin() {
-
_skyScreen->setPalette(60111);
_skyScreen->showScreen(60110);
}
@@ -340,25 +349,23 @@ void SkyEngine::handleKey(void) {
int SkyEngine::go() {
- _systemVars.quitGame = false;
-
_keyPressed.reset();
uint16 result = 0;
- if (ConfMan.hasKey("save_slot") && ConfMan.getInt("save_slot") >= 0)
- result = _skyControl->quickXRestore(ConfMan.getInt("save_slot"));
+ if (ConfMan.hasKey("save_slot")) {
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0 && saveSlot <= 999)
+ result = _skyControl->quickXRestore(ConfMan.getInt("save_slot"));
+ }
if (result != GAME_RESTORED) {
bool introSkipped = false;
if (_systemVars.gameVersion > 267) { // don't do intro for floppydemos
_skyIntro = new Intro(_skyDisk, _skyScreen, _skyMusic, _skySound, _skyText, _mixer, _system);
introSkipped = !_skyIntro->doIntro(_floppyIntro);
- _systemVars.quitGame = _skyIntro->_quitProg;
-
- delete _skyIntro;
}
- if (!_systemVars.quitGame) {
+ if (!quit()) {
_skyLogic->initScreen0();
if (introSkipped)
_skyControl->restartGame();
@@ -368,7 +375,7 @@ int SkyEngine::go() {
_lastSaveTime = _system->getMillis();
uint32 delayCount = _system->getMillis();
- while (!_systemVars.quitGame) {
+ while (!quit()) {
if (_debugger->isAttached())
_debugger->onFrame();
@@ -440,7 +447,7 @@ int SkyEngine::init() {
_floppyIntro = ConfMan.getBool("alt_intro");
_skyDisk = new Disk();
- _skySound = new Sound(_mixer, _skyDisk, ConfMan.getInt("sfx_volume"));
+ _skySound = new Sound(_mixer, _skyDisk, Audio::Mixer::kMaxChannelVolume);
_systemVars.gameVersion = _skyDisk->determineGameVersion();
@@ -475,6 +482,7 @@ int SkyEngine::init() {
_systemVars.systemFlags |= SF_PLAY_VOCS;
_systemVars.gameSpeed = 50;
+ _skyIntro = 0;
_skyCompact = new SkyCompact();
_skyText = new Text(_skyDisk, _skyCompact);
_skyMouse = new Mouse(_system, _skyDisk, _skyCompact);
@@ -615,9 +623,6 @@ void SkyEngine::delay(int32 amount) {
_skyMouse->mouseMoved(event.mouse.x, event.mouse.y);
_skyMouse->buttonPressed(1);
break;
- case Common::EVENT_QUIT:
- _systemVars.quitGame = true;
- break;
default:
break;
}
diff --git a/engines/sky/sky.h b/engines/sky/sky.h
index b5d1701930..47aebaba77 100644
--- a/engines/sky/sky.h
+++ b/engines/sky/sky.h
@@ -41,7 +41,6 @@ struct SystemVars {
uint16 gameSpeed;
uint16 currentMusic;
bool pastIntro;
- bool quitGame;
bool paused;
};
diff --git a/engines/sky/skydefs.h b/engines/sky/skydefs.h
index f4be91b3d1..f68c0f826b 100644
--- a/engines/sky/skydefs.h
+++ b/engines/sky/skydefs.h
@@ -2023,14 +2023,14 @@ namespace Sky {
#define DISQ_13 26624
#define DISQ_14 28672
#define DISQ_15 30720
-#define T0 0
-#define T1 4096
-#define T2 8192
-#define T3 12288
-#define T4 16384
-#define T5 20480
-#define T6 24576
-#define T7 28672
+//#define T0 0
+//#define T1 4096
+//#define T2 8192
+//#define T3 12288
+//#define T4 16384
+//#define T5 20480
+//#define T6 24576
+//#define T7 28672
#define UP 0
#define DOWN 1
#define LEFT 2
diff --git a/engines/sky/sound.cpp b/engines/sky/sound.cpp
index 928221a9a5..f15038c0b6 100644
--- a/engines/sky/sound.cpp
+++ b/engines/sky/sound.cpp
@@ -1025,6 +1025,7 @@ Sound::Sound(Audio::Mixer *mixer, Disk *pDisk, uint8 pVolume) {
_mixer = mixer;
_saveSounds[0] = _saveSounds[1] = 0xFFFF;
_mainSfxVolume = pVolume;
+ _isPaused = false;
}
Sound::~Sound(void) {
@@ -1254,14 +1255,20 @@ bool Sound::startSpeech(uint16 textNum) {
void Sound::fnPauseFx(void) {
- _mixer->pauseID(SOUND_CH0, true);
- _mixer->pauseID(SOUND_CH1, true);
+ if (!_isPaused) {
+ _isPaused = true;
+ _mixer->pauseID(SOUND_CH0, true);
+ _mixer->pauseID(SOUND_CH1, true);
+ }
}
void Sound::fnUnPauseFx(void) {
- _mixer->pauseID(SOUND_CH0, false);
- _mixer->pauseID(SOUND_CH1, false);
+ if (_isPaused) {
+ _isPaused = false;
+ _mixer->pauseID(SOUND_CH0, false);
+ _mixer->pauseID(SOUND_CH1, false);
+ }
}
} // End of namespace Sky
diff --git a/engines/sky/sound.h b/engines/sky/sound.h
index 28e2e8c88a..0ad509700e 100644
--- a/engines/sky/sound.h
+++ b/engines/sky/sound.h
@@ -89,6 +89,8 @@ private:
uint8 *_sampleRates, *_sfxInfo;
uint8 _mainSfxVolume;
+ bool _isPaused;
+
static uint16 _speechConvertTable[8];
static SfxQueue _sfxQueue[MAX_QUEUED_FX];
};
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 2bb027ddb4..3e15429e44 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -189,7 +189,7 @@ bool MoviePlayer::load(uint32 id) {
int lastEnd = -1;
_movieTexts.clear();
- while (f.readLine(line, sizeof(line))) {
+ while (f.readLine_OLD(line, sizeof(line))) {
lineNo++;
if (line[0] == '#' || line[0] == 0) {
continue;
@@ -300,9 +300,6 @@ void MoviePlayer::play(void) {
terminated = true;
}
break;
- case Common::EVENT_QUIT:
- _system->quit();
- break;
default:
break;
}
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp
index 980e0b4f9f..d0808d3ece 100644
--- a/engines/sword1/control.cpp
+++ b/engines/sword1/control.cpp
@@ -215,7 +215,7 @@ void Control::askForCd(void) {
notAccepted = false;
}
}
- } while (notAccepted && (!SwordEngine::_systemVars.engineQuit));
+ } while (notAccepted && (!g_engine->quit()));
_resMan->resClose(fontId);
free(_screenBuf);
@@ -317,7 +317,7 @@ uint8 Control::runPanel(void) {
}
delay(1000 / 12);
newMode = getClicks(mode, &retVal);
- } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!SwordEngine::_systemVars.engineQuit));
+ } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!g_engine->quit()));
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
uint8 volL, volR;
@@ -425,7 +425,7 @@ uint8 Control::handleButtonClick(uint8 id, uint8 mode, uint8 *retVal) {
_buttons[5]->setSelected(SwordEngine::_systemVars.showText);
} else if (id == BUTTON_QUIT) {
if (getConfirm(_lStrings[STR_QUIT]))
- SwordEngine::_systemVars.engineQuit = true;
+ g_engine->quitGame();
return mode;
}
break;
@@ -703,7 +703,7 @@ void Control::handleSaveKey(Common::KeyState kbd) {
bool Control::saveToFile(void) {
if ((_selectedSavegame == 255) || !strlen((char*)_saveNames[_selectedSavegame]))
return false; // no saveslot selected or no name entered
- saveGameToFile(_selectedSavegame);
+ saveGameToFile(_numSaves);
writeSavegameDescriptions();
return true;
}
@@ -741,6 +741,7 @@ void Control::readSavegameDescriptions(void) {
curFileNum++;
} while ((ch != 255) && (!inf->eos()));
_saveFiles = curFileNum;
+ _numSaves = _saveFiles;
}
delete inf;
}
@@ -1091,9 +1092,6 @@ void Control::delay(uint32 msecs) {
_mouseDown = false;
_mouseState |= BS1_WHEEL_DOWN;
break;
- case Common::EVENT_QUIT:
- SwordEngine::_systemVars.engineQuit = true;
- break;
default:
break;
}
diff --git a/engines/sword1/control.h b/engines/sword1/control.h
index 7d9af2f199..926db757b9 100644
--- a/engines/sword1/control.h
+++ b/engines/sword1/control.h
@@ -98,6 +98,7 @@ private:
void deselectSaveslots(void);
uint8 *_restoreBuf;
uint8 _saveFiles;
+ uint8 _numSaves;
uint8 _saveScrollPos;
uint8 _selectedSavegame;
uint8 _saveNames[64][32];
diff --git a/engines/sword1/credits.cpp b/engines/sword1/credits.cpp
index 14dd0ecd2b..258784ab53 100644
--- a/engines/sword1/credits.cpp
+++ b/engines/sword1/credits.cpp
@@ -125,7 +125,7 @@ void CreditsPlayer::play(void) {
uint16 renderY = BUFSIZE_Y / 2;
uint16 clearY = 0xFFFF;
bool clearLine = false;
- while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) {
+ while (((*textData != FNT_EOB) || (scrollY != renderY)) && !g_engine->quit()) {
if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio
if (scrollY < BUFSIZE_Y - CREDITS_Y)
_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);
@@ -175,7 +175,7 @@ void CreditsPlayer::play(void) {
uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);
uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);
_palLen /= 3;
- while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) {
+ while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !g_engine->quit()) {
delay(100);
}
memset(_palette, 0, 256 * 4);
@@ -184,13 +184,13 @@ void CreditsPlayer::play(void) {
_system->updateScreen();
fadePalette(revoPal, true, _palLen);
- while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) {
+ while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !g_engine->quit()) {
delay(100);
}
fadePalette(revoPal, false, _palLen);
delay(3000);
- if (SwordEngine::_systemVars.engineQuit)
+ if (g_engine->quit())
_mixer->stopAll();
free(revoBuf);
}
@@ -200,7 +200,7 @@ void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {
int fadeStart = fadeup ? 0 : 12;
int relDelay = _system->getMillis();
- for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) {
+ for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !g_engine->quit(); fadeStep += fadeDir) {
for (uint16 cnt = 0; cnt < len * 3; cnt++)
_palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;
_system->setPalette(_palette, 0, 256);
@@ -280,13 +280,12 @@ void CreditsPlayer::delay(int msecs) {
do {
Common::EventManager *eventMan = _system->getEventManager();
while (eventMan->pollEvent(event)) {
+#if 0
switch (event.type) {
- case Common::EVENT_QUIT:
- SwordEngine::_systemVars.engineQuit = true;
- break;
default:
break;
}
+#endif
}
_system->updateScreen();
@@ -294,7 +293,7 @@ void CreditsPlayer::delay(int msecs) {
if (msecs > 0)
_system->delayMillis(10);
- } while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit);
+ } while ((_system->getMillis() < start + msecs) && !g_engine->quit());
}
ArcFile::ArcFile(void) {
diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp
index e7e1fb39a4..2fa108ebdd 100644
--- a/engines/sword1/logic.cpp
+++ b/engines/sword1/logic.cpp
@@ -1636,7 +1636,7 @@ int Logic::fnQuitGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d,
if (SwordEngine::_systemVars.isDemo) {
GUI::MessageDialog dialog("This is the end of the Broken Sword 1 Demo", "OK", NULL);
dialog.runModal();
- SwordEngine::_systemVars.engineQuit = true;
+ g_engine->quitGame();
} else
error("fnQuitGame() called");
return fnQuit(cpt, id, 0, 0, 0, 0, 0, 0);
diff --git a/engines/sword1/music.cpp b/engines/sword1/music.cpp
index 6cb82bc0b0..27e7568fcc 100644
--- a/engines/sword1/music.cpp
+++ b/engines/sword1/music.cpp
@@ -80,7 +80,7 @@ BaseAudioStream::~BaseAudioStream() {
void BaseAudioStream::reinit(int size, int rate, byte flags) {
_isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0;
_rate = rate;
- assert((uint)size <= (_sourceStream->size() - _sourceStream->pos()));
+ assert(size <= (_sourceStream->size() - _sourceStream->pos()));
_bitsPerSample = ((flags & Audio::Mixer::FLAG_16BITS) != 0) ? 16 : 8;
_samplesLeft = (size * 8) / _bitsPerSample;
if ((_bitsPerSample != 16) && (_bitsPerSample != 8))
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 7372779199..9b79f59a32 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -32,6 +32,7 @@
#include "common/fs.h"
#include "common/timer.h"
#include "common/events.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "engines/metaengine.h"
@@ -94,13 +95,22 @@ public:
return "Broken Sword Games (C) Revolution";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const FSList &fslist) const;
+ virtual GameList detectGames(const Common::FSList &fslist) const;
+ virtual SaveStateList listSaves(const char *target) const;
virtual PluginError createInstance(OSystem *syst, Engine **engine) const;
};
+bool SwordMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad);
+}
+
GameList SwordMetaEngine::getSupportedGames() const {
GameList games;
games.push_back(sword1FullSettings);
@@ -122,8 +132,8 @@ GameDescriptor SwordMetaEngine::findGame(const char *gameid) const {
return GameDescriptor();
}
-void Sword1CheckDirectory(const FSList &fslist, bool *filesFound) {
- for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound) {
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (!file->isDirectory()) {
const char *fileName = file->getName().c_str();
for (int cnt = 0; cnt < NUM_FILES_TO_CHECK; cnt++)
@@ -132,15 +142,15 @@ void Sword1CheckDirectory(const FSList &fslist, bool *filesFound) {
} else {
for (int cnt = 0; cnt < ARRAYSIZE(g_dirNames); cnt++)
if (scumm_stricmp(file->getName().c_str(), g_dirNames[cnt]) == 0) {
- FSList fslist2;
- if (file->getChildren(fslist2, FilesystemNode::kListFilesOnly))
+ Common::FSList fslist2;
+ if (file->getChildren(fslist2, Common::FilesystemNode::kListFilesOnly))
Sword1CheckDirectory(fslist2, filesFound);
}
}
}
}
-GameList SwordMetaEngine::detectGames(const FSList &fslist) const {
+GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
int i, j;
GameList detectedGames;
bool filesFound[NUM_FILES_TO_CHECK];
@@ -187,6 +197,47 @@ PluginError SwordMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
return kNoError;
}
+SaveStateList SwordMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ SaveStateList saveList;
+
+ Common::String pattern = "SAVEGAME.???";
+ Common::StringList filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end());
+ Common::StringList::const_iterator file = filenames.begin();
+
+ Common::InSaveFile *in = saveFileMan->openForLoading("SAVEGAME.INF");
+ if (in) {
+ uint8 stop;
+ char saveDesc[32];
+ do {
+ // Obtain the last digit of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 1);
+
+ uint pos = 0;
+ do {
+ stop = in->readByte();
+ if (pos < (sizeof(saveDesc) - 1)) {
+ if ((stop == 10) || (stop == 255) || (in->eos())) {
+ saveDesc[pos++] = '\0';
+ }
+ else if (stop >= 32) {
+ saveDesc[pos++] = stop;
+ }
+ }
+ } while ((stop != 10) && (stop != 255) && (!in->eos()));
+ if (saveDesc[0] != 0) {
+ saveList.push_back(SaveStateDescriptor(slotNum, saveDesc, *file));
+ file++;
+ }
+ } while ((stop != 255) && (!in->eos()));
+ }
+
+ delete in;
+
+ return saveList;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(SWORD1)
REGISTER_PLUGIN_DYNAMIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine);
#else
@@ -206,14 +257,14 @@ SwordEngine::SwordEngine(OSystem *syst)
_features = 0;
// Add default file directories
- Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/");
- Common::File::addDefaultDirectory(_gameDataPath + "MUSIC/");
- Common::File::addDefaultDirectory(_gameDataPath + "SPEECH/");
- Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/");
- Common::File::addDefaultDirectory(_gameDataPath + "clusters/");
- Common::File::addDefaultDirectory(_gameDataPath + "music/");
- Common::File::addDefaultDirectory(_gameDataPath + "speech/");
- Common::File::addDefaultDirectory(_gameDataPath + "video/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("MUSIC"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("SPEECH"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("music"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("speech"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("video"));
}
SwordEngine::~SwordEngine() {
@@ -247,8 +298,6 @@ int SwordEngine::init() {
_resMan = new ResMan("swordres.rif", _systemVars.isMac);
debug(5, "Starting object manager");
_objectMan = new ObjectMan(_resMan);
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, Audio::Mixer::kMaxMixerVolume);
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
_mouse = new Mouse(_system, _resMan, _objectMan);
_screen = new Screen(_system, _resMan, _objectMan);
_music = new Music(_mixer);
@@ -257,60 +306,13 @@ int SwordEngine::init() {
_logic = new Logic(_objectMan, _resMan, _screen, _mouse, _sound, _music, _menu, _system, _mixer);
_mouse->useLogicAndMenu(_logic, _menu);
- uint musicVol = ConfMan.getInt("music_volume");
- uint speechVol = ConfMan.getInt("speech_volume");
- uint sfxVol = ConfMan.getInt("sfx_volume");
- uint musicBal = 50;
- if (ConfMan.hasKey("music_balance")) {
- musicBal = CLIP(ConfMan.getInt("music_balance"), 0, 100);
- }
- uint speechBal = 50;
- if (ConfMan.hasKey("speech_balance")) {
- speechBal = CLIP(ConfMan.getInt("speech_balance"), 0, 100);
- }
- uint sfxBal = 50;
- if (ConfMan.hasKey("sfx_balance")) {
- sfxBal = CLIP(ConfMan.getInt("sfx_balance"), 0, 100);
- }
-
- uint musicVolL = 2 * musicVol * musicBal / 100;
- uint musicVolR = 2 * musicVol - musicVolL;
-
- uint speechVolL = 2 * speechVol * speechBal / 100;
- uint speechVolR = 2 * speechVol - speechVolL;
-
- uint sfxVolL = 2 * sfxVol * sfxBal / 100;
- uint sfxVolR = 2 * sfxVol - sfxVolL;
-
- if (musicVolR > 255) {
- musicVolR = 255;
- }
- if (musicVolL > 255) {
- musicVolL = 255;
- }
- if (speechVolR > 255) {
- speechVolR = 255;
- }
- if (speechVolL > 255) {
- speechVolL = 255;
- }
- if (sfxVolR > 255) {
- sfxVolR = 255;
- }
- if (sfxVolL > 255) {
- sfxVolL = 255;
- }
-
- _music->setVolume(musicVolL, musicVolR);
- _sound->setSpeechVol(speechVolL, speechVolR);
- _sound->setSfxVol(sfxVolL, sfxVolR);
+ syncSoundSettings();
_systemVars.justRestoredGame = 0;
_systemVars.currentCD = 0;
_systemVars.controlPanelMode = CP_NEWGAME;
_systemVars.forceRestart = false;
_systemVars.wantFade = true;
- _systemVars.engineQuit = false;
switch (Common::parseLanguage(ConfMan.get("language"))) {
case Common::DE_DEU:
@@ -358,6 +360,62 @@ void SwordEngine::reinitialize(void) {
_systemVars.wantFade = true;
}
+void SwordEngine::syncSoundSettings() {
+ uint musicVol = ConfMan.getInt("music_volume");
+ uint sfxVol = ConfMan.getInt("sfx_volume");
+ uint speechVol = ConfMan.getInt("speech_volume");
+
+ uint musicBal = 50;
+ if (ConfMan.hasKey("music_balance")) {
+ musicBal = CLIP(ConfMan.getInt("music_balance"), 0, 100);
+ }
+
+ uint speechBal = 50;
+ if (ConfMan.hasKey("speech_balance")) {
+ speechBal = CLIP(ConfMan.getInt("speech_balance"), 0, 100);
+ }
+ uint sfxBal = 50;
+ if (ConfMan.hasKey("sfx_balance")) {
+ sfxBal = CLIP(ConfMan.getInt("sfx_balance"), 0, 100);
+ }
+
+ uint musicVolL = 2 * musicVol * musicBal / 100;
+ uint musicVolR = 2 * musicVol - musicVolL;
+
+ uint speechVolL = 2 * speechVol * speechBal / 100;
+ uint speechVolR = 2 * speechVol - speechVolL;
+
+ uint sfxVolL = 2 * sfxVol * sfxBal / 100;
+ uint sfxVolR = 2 * sfxVol - sfxVolL;
+
+ if (musicVolR > 255) {
+ musicVolR = 255;
+ }
+ if (musicVolL > 255) {
+ musicVolL = 255;
+ }
+
+ if (speechVolR > 255) {
+ speechVolR = 255;
+ }
+ if (speechVolL > 255) {
+ speechVolL = 255;
+ }
+ if (sfxVolR > 255) {
+ sfxVolR = 255;
+ }
+ if (sfxVolL > 255) {
+ sfxVolL = 255;
+ }
+
+ _music->setVolume(musicVolL, musicVolR);
+ _sound->setSpeechVol(speechVolL, speechVolR);
+ _sound->setSfxVol(sfxVolL, sfxVolR);
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+}
+
void SwordEngine::flagsToBool(bool *dest, uint8 flags) {
uint8 bitPos = 0;
while (flags) {
@@ -639,13 +697,13 @@ int SwordEngine::go() {
int saveSlot = ConfMan.getInt("save_slot");
// Savegames are numbered starting from 1 in the dialog window,
// but their filenames are numbered starting from 0.
- if (saveSlot > 0 && _control->restoreGameFromFile(saveSlot - 1)) {
+ if (saveSlot >= 0 && _control->savegamesExist() && _control->restoreGameFromFile(saveSlot)) {
_control->doRestore();
} else if (_control->savegamesExist()) {
_systemVars.controlPanelMode = CP_NEWGAME;
if (_control->runPanel() == CONTROL_GAME_RESTORED)
_control->doRestore();
- else if (!_systemVars.engineQuit)
+ else if (!quit())
_logic->startPositions(0);
} else {
// no savegames, start new game.
@@ -654,10 +712,10 @@ int SwordEngine::go() {
}
_systemVars.controlPanelMode = CP_NORMAL;
- while (!_systemVars.engineQuit) {
+ while (!quit()) {
uint8 action = mainLoop();
- if (!_systemVars.engineQuit) {
+ if (!quit()) {
// the mainloop was left, we have to reinitialize.
reinitialize();
if (action == CONTROL_GAME_RESTORED)
@@ -698,7 +756,7 @@ uint8 SwordEngine::mainLoop(void) {
uint8 retCode = 0;
_keyPressed.reset();
- while ((retCode == 0) && (!_systemVars.engineQuit)) {
+ while ((retCode == 0) && (!quit())) {
// do we need the section45-hack from sword.c here?
checkCd();
@@ -747,9 +805,9 @@ uint8 SwordEngine::mainLoop(void) {
}
_mouseState = 0;
_keyPressed.reset();
- } while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!_systemVars.engineQuit));
+ } while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!quit()));
- if ((retCode == 0) && (Logic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade && (!_systemVars.engineQuit)) {
+ if ((retCode == 0) && (Logic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade && (!quit())) {
_screen->fadeDownPalette();
int32 relDelay = (int32)_system->getMillis();
while (_screen->stillFading()) {
@@ -796,9 +854,6 @@ void SwordEngine::delay(int32 amount) { //copied and mutilated from sky.cpp
_mouseState |= BS1R_BUTTON_UP;
_mouseCoord = event.mouse;
break;
- case Common::EVENT_QUIT:
- _systemVars.engineQuit = true;
- break;
default:
break;
}
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index cfb6750a47..5bc80b4f6d 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -58,7 +58,6 @@ struct SystemVars {
bool runningFromCd;
uint32 currentCD; // starts at zero, then either 1 or 2 depending on section being played
uint32 justRestoredGame; // see main() in sword.c & New_screen() in gtm_core.c
- bool engineQuit;
uint8 controlPanelMode; // 1 death screen version of the control panel, 2 = successful end of game, 3 = force restart
bool forceRestart;
@@ -78,6 +77,7 @@ public:
virtual ~SwordEngine();
static SystemVars _systemVars;
void reinitialize(void);
+ virtual void syncSoundSettings();
uint32 _features;
protected:
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 48196a2f7d..76f14851e7 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -357,8 +357,8 @@ bool MoviePlayer::userInterrupt() {
case Common::EVENT_SCREEN_CHANGED:
handleScreenChanged();
break;
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
- _vm->closeGame();
terminate = true;
break;
case Common::EVENT_KEYDOWN:
@@ -379,7 +379,7 @@ void MoviePlayer::play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn
bool startNextText = false;
// This happens if the user quits during the "eye" cutscene.
- if (_vm->_quit)
+ if (_vm->quit())
return;
_numSpeechLines = numLines;
diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp
index 6b466d6be0..dcacbc78d4 100644
--- a/engines/sword2/controls.cpp
+++ b/engines/sword2/controls.cpp
@@ -396,7 +396,7 @@ int Dialog::runModal() {
_vm->_system->delayMillis(20);
- if (_vm->_quit)
+ if (_vm->quit())
setResult(0);
}
@@ -842,7 +842,7 @@ int StartDialog::runModal() {
if (startDialog.runModal())
return 1;
- if (_vm->_quit)
+ if (_vm->quit())
return 0;
RestoreDialog restoreDialog(_vm);
@@ -850,7 +850,7 @@ int StartDialog::runModal() {
if (restoreDialog.runModal())
return 0;
- if (_vm->_quit)
+ if (_vm->quit())
return 0;
}
@@ -882,7 +882,7 @@ int QuitDialog::runModal() {
int result = MiniDialog::runModal();
if (result)
- _vm->closeGame();
+ _vm->quitGame();
return result;
}
diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp
index 84a5b5af76..31b799386f 100644
--- a/engines/sword2/function.cpp
+++ b/engines/sword2/function.cpp
@@ -2388,7 +2388,7 @@ int32 Logic::fnPlayCredits(int32 *params) {
// params: none
if (readVar(DEMO)) {
- _vm->closeGame();
+ _vm->quitGame();
return IR_STOP;
}
diff --git a/engines/sword2/palette.cpp b/engines/sword2/palette.cpp
index 81f93c77ae..b66a3c9a81 100644
--- a/engines/sword2/palette.cpp
+++ b/engines/sword2/palette.cpp
@@ -212,7 +212,7 @@ uint8 Screen::getFadeStatus() {
}
void Screen::waitForFade() {
- while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->_quit) {
+ while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->quit()) {
updateDisplay();
_vm->_system->delayMillis(20);
}
diff --git a/engines/sword2/resman.cpp b/engines/sword2/resman.cpp
index 8cddddff78..326f90cd82 100644
--- a/engines/sword2/resman.cpp
+++ b/engines/sword2/resman.cpp
@@ -113,7 +113,7 @@ bool ResourceManager::init() {
// The resource.inf file is a simple text file containing the names of
// all the resource files.
- while (file.readLine(_resFiles[_totalClusters].fileName, sizeof(_resFiles[_totalClusters].fileName))) {
+ while (file.readLine_OLD(_resFiles[_totalClusters].fileName, sizeof(_resFiles[_totalClusters].fileName))) {
_resFiles[_totalClusters].numEntries = -1;
_resFiles[_totalClusters].entryTab = NULL;
if (++_totalClusters >= MAX_res_files) {
@@ -412,7 +412,7 @@ Common::File *ResourceManager::openCluFile(uint16 fileNum) {
// quit while the game is asking for the user to insert a CD.
// But recovering from this situation gracefully is just too
// much trouble, so quit now.
- if (_vm->_quit)
+ if (_vm->quit())
g_system->quit();
// If the file is supposed to be on hard disk, or we're
diff --git a/engines/sword2/screen.cpp b/engines/sword2/screen.cpp
index fdabb3ee6f..1faef01939 100644
--- a/engines/sword2/screen.cpp
+++ b/engines/sword2/screen.cpp
@@ -389,7 +389,7 @@ void Screen::displayMsg(byte *text, int time) {
uint32 targetTime = _vm->getMillis() + (time * 1000);
_vm->sleepUntil(targetTime);
} else {
- while (!_vm->_quit) {
+ while (!_vm->quit()) {
MouseEvent *me = _vm->mouseEvent();
if (me && (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN)))
break;
@@ -919,7 +919,7 @@ void Screen::rollCredits() {
while (1) {
char buffer[80];
- char *line = f.readLine(buffer, sizeof(buffer));
+ char *line = f.readLine_OLD(buffer, sizeof(buffer));
if (!line || *line == 0) {
if (!hasCenterMark) {
@@ -1035,7 +1035,7 @@ void Screen::rollCredits() {
uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps);
- while (scrollPos < scrollSteps && !_vm->_quit) {
+ while (scrollPos < scrollSteps && !_vm->quit()) {
clearScene();
for (i = startLine; i < lineCount; i++) {
@@ -1123,13 +1123,13 @@ void Screen::rollCredits() {
// The music should either have stopped or be about to stop, so
// wait for it to really happen.
- while (_vm->_sound->musicTimeRemaining() && !_vm->_quit) {
+ while (_vm->_sound->musicTimeRemaining() && !_vm->quit()) {
updateDisplay(false);
_vm->_system->delayMillis(100);
}
}
- if (_vm->_quit)
+ if (_vm->quit())
return;
waitForFade();
diff --git a/engines/sword2/sound.h b/engines/sword2/sound.h
index b89ef8f12b..684be3dacd 100644
--- a/engines/sword2/sound.h
+++ b/engines/sword2/sound.h
@@ -124,7 +124,7 @@ struct SoundFileHandle {
Common::File file;
uint32 *idxTab;
uint32 idxLen;
- uint32 fileSize;
+ int32 fileSize;
uint32 fileType;
volatile bool inUse;
};
diff --git a/engines/sword2/startup.cpp b/engines/sword2/startup.cpp
index 1841384897..09bf65bf75 100644
--- a/engines/sword2/startup.cpp
+++ b/engines/sword2/startup.cpp
@@ -64,19 +64,23 @@ bool Sword2Engine::initStartMenu() {
// extract the filenames
int start_ids[MAX_starts];
- char buf[10];
-
int lineno = 0;
- while (fp.readLine(buf, sizeof(buf))) {
+ while (!fp.eos() && !fp.ioFailed()) {
+ Common::String line = fp.readLine();
+
+ // Skip empty lines or, more likely, the end of the stream.
+ if (line.size() == 0)
+ continue;
+
char *errptr;
int id;
lineno++;
- id = strtol(buf, &errptr, 10);
+ id = strtol(line.c_str(), &errptr, 10);
if (*errptr) {
- warning("startup.inf:%d: Invalid string '%s'", lineno, buf);
+ warning("startup.inf:%d: Invalid string '%s'", lineno, line.c_str());
continue;
}
@@ -98,6 +102,10 @@ bool Sword2Engine::initStartMenu() {
}
}
+ // An I/O error before EOS? That's bad, but this is not a vital file.
+ if (fp.ioFailed() && !fp.eos())
+ warning("I/O error while reading startup.inf");
+
fp.close();
// Using this method the Gode generated resource.inf must have #0d0a
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index 7331d1f761..dc884eaacb 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -33,6 +33,7 @@
#include "common/file.h"
#include "common/fs.h"
#include "common/events.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "engines/metaengine.h"
@@ -79,13 +80,24 @@ public:
return "Broken Sword Games (C) Revolution";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual GameList getSupportedGames() const;
virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const FSList &fslist) const;
+ virtual GameList detectGames(const Common::FSList &fslist) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
virtual PluginError createInstance(OSystem *syst, Engine **engine) const;
};
+bool Sword2MetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
GameList Sword2MetaEngine::getSupportedGames() const {
const Sword2::GameSettings *g = Sword2::sword2_settings;
GameList games;
@@ -106,10 +118,10 @@ GameDescriptor Sword2MetaEngine::findGame(const char *gameid) const {
return GameDescriptor(g->gameid, g->description);
}
-GameList Sword2MetaEngine::detectGames(const FSList &fslist) const {
+GameList Sword2MetaEngine::detectGames(const Common::FSList &fslist) const {
GameList detectedGames;
const Sword2::GameSettings *g;
- FSList::const_iterator file;
+ Common::FSList::const_iterator file;
// TODO: It would be nice if we had code here which distinguishes
// between the 'sword2' and 'sword2demo' targets. The current code
@@ -139,8 +151,8 @@ GameList Sword2MetaEngine::detectGames(const FSList &fslist) const {
const char *fileName = file->getName().c_str();
if (0 == scumm_stricmp("clusters", fileName)) {
- FSList recList;
- if (file->getChildren(recList, FilesystemNode::kListAll)) {
+ Common::FSList recList;
+ if (file->getChildren(recList, Common::FilesystemNode::kListAll)) {
GameList recGames(detectGames(recList));
if (!recGames.empty()) {
detectedGames.push_back(recGames);
@@ -156,13 +168,52 @@ GameList Sword2MetaEngine::detectGames(const FSList &fslist) const {
return detectedGames;
}
+SaveStateList Sword2MetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[SAVE_DESCRIPTION_LEN];
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ in->readUint32LE();
+ in->read(saveDesc, SAVE_DESCRIPTION_LEN);
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void Sword2MetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[6];
+ snprintf(extension, sizeof(extension), ".%03d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
PluginError Sword2MetaEngine::createInstance(OSystem *syst, Engine **engine) const {
assert(syst);
assert(engine);
- FSList fslist;
- FilesystemNode dir(ConfMan.get("path"));
- if (!dir.getChildren(fslist, FilesystemNode::kListAll)) {
+ Common::FSList fslist;
+ Common::FilesystemNode dir(ConfMan.get("path"));
+ if (!dir.getChildren(fslist, Common::FilesystemNode::kListAll)) {
return kInvalidPathError;
}
@@ -190,12 +241,12 @@ namespace Sword2 {
Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) {
// Add default file directories
- Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/");
- Common::File::addDefaultDirectory(_gameDataPath + "SWORD2/");
- Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/");
- Common::File::addDefaultDirectory(_gameDataPath + "clusters/");
- Common::File::addDefaultDirectory(_gameDataPath + "sword2/");
- Common::File::addDefaultDirectory(_gameDataPath + "video/");
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("CLUSTERS"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("SWORD2"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("VIDEO"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("clusters"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("sword2"));
+ Common::File::addDefaultDirectory(_gameDataDir.getChild("video"));
if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword2demo"))
_features = GF_DEMO;
@@ -229,7 +280,6 @@ Sword2Engine::Sword2Engine(OSystem *syst) : Engine(syst) {
_gameCycle = 0;
_gameSpeed = 1;
- _quit = false;
syst->getEventManager()->registerRandomSource(_rnd, "sword2");
}
@@ -371,7 +421,7 @@ int Sword2Engine::init() {
// player will kill the music for us. Otherwise, the restore
// will either have killed the music, or done a crossfade.
- if (_quit)
+ if (quit())
return 0;
if (result)
@@ -443,7 +493,7 @@ int Sword2Engine::go() {
// because we want the break to happen before updating the
// screen again.
- if (_quit)
+ if (quit())
break;
// creates the debug text blocks
@@ -463,10 +513,6 @@ int Sword2Engine::go() {
return 0;
}
-void Sword2Engine::closeGame() {
- _quit = true;
-}
-
void Sword2Engine::restartGame() {
ScreenInfo *screenInfo = _screen->getScreenInfo();
uint32 temp_demo_flag;
@@ -610,9 +656,6 @@ void Sword2Engine::parseInputEvents() {
_mouseEvent.buttons = RD_WHEELDOWN;
}
break;
- case Common::EVENT_QUIT:
- closeGame();
- break;
default:
break;
}
diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h
index 05c5d7fa47..9b589c347e 100644
--- a/engines/sword2/sword2.h
+++ b/engines/sword2/sword2.h
@@ -141,8 +141,6 @@ public:
bool getSubtitles() { return _useSubtitles; }
void setSubtitles(bool b) { _useSubtitles = b; }
- bool _quit;
-
uint32 _features;
MemoryManager *_memory;
@@ -210,7 +208,6 @@ public:
void startGame();
void gameCycle();
- void closeGame();
void restartGame();
void sleepUntil(uint32 time);
diff --git a/engines/tinsel/config.cpp b/engines/tinsel/config.cpp
index 4c143f1b8d..803d2231e4 100644
--- a/engines/tinsel/config.cpp
+++ b/engines/tinsel/config.cpp
@@ -24,8 +24,6 @@
* This file contains configuration functionality
*/
-//#define USE_3FLAGS 1
-
#include "tinsel/config.h"
#include "tinsel/dw.h"
#include "tinsel/sound.h"
@@ -41,13 +39,13 @@ namespace Tinsel {
//----------------- GLOBAL GLOBAL DATA --------------------
int dclickSpeed = DOUBLE_CLICK_TIME;
-int volMidi = MAXMIDIVOL;
-int volSound = MAXSAMPVOL;
-int volVoice = MAXSAMPVOL;
+int volMidi = Audio::Mixer::kMaxChannelVolume;
+int volSound = Audio::Mixer::kMaxChannelVolume;
+int volVoice = Audio::Mixer::kMaxChannelVolume;
int speedText = DEFTEXTSPEED;
int bSubtitles = false;
int bSwapButtons = 0;
-LANGUAGE language = TXT_ENGLISH;
+LANGUAGE g_language = TXT_ENGLISH;
int bAmerica = 0;
@@ -55,19 +53,43 @@ int bAmerica = 0;
bool bNoBlocking;
/**
- * WriteConfig()
+ * Write settings to config manager and flush the config file to disk.
*/
-
void WriteConfig(void) {
ConfMan.setInt("dclick_speed", dclickSpeed);
- ConfMan.setInt("music_volume", (volMidi * Audio::Mixer::kMaxChannelVolume) / MAXMIDIVOL);
- ConfMan.setInt("sfx_volume", (volSound * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL);
- ConfMan.setInt("speech_volume", (volVoice * Audio::Mixer::kMaxChannelVolume) / MAXSAMPVOL);
+ ConfMan.setInt("music_volume", volMidi);
+ ConfMan.setInt("sfx_volume", volSound);
+ ConfMan.setInt("speech_volume", volVoice);
ConfMan.setInt("talkspeed", (speedText * 255) / 100);
ConfMan.setBool("subtitles", bSubtitles);
//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0);
- //ConfigData.language = language; // not necessary, as language has been set in the launcher
//ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB
+
+ // Store language for multilingual versions
+ if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) {
+ Common::Language lang;
+ switch (g_language) {
+ case TXT_FRENCH:
+ lang = Common::FR_FRA;
+ break;
+ case TXT_GERMAN:
+ lang = Common::DE_DEU;
+ break;
+ case TXT_SPANISH:
+ lang = Common::ES_ESP;
+ break;
+ case TXT_ITALIAN:
+ lang = Common::IT_ITA;
+ break;
+ default:
+ lang = Common::EN_ANY;
+ }
+
+ ConfMan.set("language", Common::getLanguageCode(lang));
+ }
+
+ // Write to disk
+ ConfMan.flushToDisk();
}
/*---------------------------------------------------------------------*\
@@ -79,9 +101,9 @@ void ReadConfig(void) {
if (ConfMan.hasKey("dclick_speed"))
dclickSpeed = ConfMan.getInt("dclick_speed");
- volMidi = (ConfMan.getInt("music_volume") * MAXMIDIVOL) / Audio::Mixer::kMaxChannelVolume;
- volSound = (ConfMan.getInt("sfx_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume;
- volVoice = (ConfMan.getInt("speech_volume") * MAXSAMPVOL) / Audio::Mixer::kMaxChannelVolume;
+ volMidi = ConfMan.getInt("music_volume");
+ volSound = ConfMan.getInt("sfx_volume");
+ volVoice = ConfMan.getInt("speech_volume");
if (ConfMan.hasKey("talkspeed"))
speedText = (ConfMan.getInt("talkspeed") * 100) / 255;
@@ -94,24 +116,53 @@ void ReadConfig(void) {
//ConfigData.language = language; // not necessary, as language has been set in the launcher
//ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB
-// The flags here control how many country flags are displayed in one of the option dialogs.
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
- language = ConfigData.language;
- #ifdef USE_3FLAGS
- if (language == TXT_ENGLISH || language == TXT_ITALIAN) {
- language = TXT_GERMAN;
- bSubtitles = true;
+ // Set language - we'll be clever here and use the ScummVM language setting
+ g_language = TXT_ENGLISH;
+ Common::Language lang = _vm->getLanguage();
+ if (lang == Common::UNK_LANG && ConfMan.hasKey("language"))
+ lang = Common::parseLanguage(ConfMan.get("language")); // For multi-lingual versions, fall back to user settings
+ switch (lang) {
+ case Common::FR_FRA:
+ g_language = TXT_FRENCH;
+ break;
+ case Common::DE_DEU:
+ g_language = TXT_GERMAN;
+ break;
+ case Common::ES_ESP:
+ g_language = TXT_SPANISH;
+ break;
+ case Common::IT_ITA:
+ g_language = TXT_ITALIAN;
+ break;
+ default:
+ g_language = TXT_ENGLISH;
}
- #endif
- #ifdef USE_4FLAGS
- if (language == TXT_ENGLISH) {
- language = TXT_GERMAN;
+
+ if (lang == Common::JA_JPN) {
+ // TODO: Add support for JAPAN version
+ } else if (lang == Common::HB_ISR) {
+ // TODO: Add support for HEBREW version
+
+ // The Hebrew version appears to the software as being English
+ // but it needs to have subtitles on...
+ g_language = TXT_ENGLISH;
bSubtitles = true;
+ } else if (_vm->getFeatures() & GF_USE_3FLAGS) {
+ // 3 FLAGS version supports French, German, Spanish
+ // Fall back to German if necessary
+ if (g_language != TXT_FRENCH && g_language != TXT_GERMAN && g_language != TXT_SPANISH) {
+ g_language = TXT_GERMAN;
+ bSubtitles = true;
+ }
+ } else if (_vm->getFeatures() & GF_USE_4FLAGS) {
+ // 4 FLAGS version supports French, German, Spanish, Italian
+ // Fall back to German if necessary
+ if (g_language != TXT_FRENCH && g_language != TXT_GERMAN &&
+ g_language != TXT_SPANISH && g_language != TXT_ITALIAN) {
+ g_language = TXT_GERMAN;
+ bSubtitles = true;
+ }
}
- #endif
-#else
- language = TXT_ENGLISH;
-#endif
}
bool isJapanMode() {
diff --git a/engines/tinsel/config.h b/engines/tinsel/config.h
index 73cc411cb6..fc85f0abe0 100644
--- a/engines/tinsel/config.h
+++ b/engines/tinsel/config.h
@@ -30,23 +30,11 @@
namespace Tinsel {
-// None of these defined -> 1 language, in ENGLISH.TXT
-//#define USE_5FLAGS 1 // All 5 flags
-//#define USE_4FLAGS 1 // French, German, Italian, Spanish
-//#define USE_3FLAGS 1 // French, German, Spanish
-
-// The Hebrew version appears to the software as being English
-// but it needs to have subtitles on...
-//#define HEBREW 1
-
-//#define JAPAN 1
-
-
// double click timer initial value
-#define DOUBLE_CLICK_TIME 6 // 6 @ 18Hz = .33 sec
-
-#define DEFTEXTSPEED 0
-
+enum {
+ DOUBLE_CLICK_TIME = 6, // 6 @ 18Hz = .33 sec
+ DEFTEXTSPEED = 0
+};
extern int dclickSpeed;
extern int volMidi;
@@ -55,7 +43,7 @@ extern int volVoice;
extern int speedText;
extern int bSubtitles;
extern int bSwapButtons;
-extern LANGUAGE language;
+extern LANGUAGE g_language;
extern int bAmerica;
void WriteConfig(void);
diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp
index b95662cbfe..f933b2dd79 100644
--- a/engines/tinsel/cursor.cpp
+++ b/engines/tinsel/cursor.cpp
@@ -49,7 +49,7 @@ namespace Tinsel {
//----------------- LOCAL DEFINES --------------------
#define ITERATION_BASE FRAC_ONE
-#define ITER_ACCELLERATION (10L << (FRAC_BITS - 4))
+#define ITER_ACCELERATION (10L << (FRAC_BITS - 4))
//----------------- LOCAL GLOBAL DATA --------------------
@@ -404,7 +404,8 @@ static void MoveCursor(void) {
newY = intToFrac(ptMouse.y);
// modify mouse driver position depending on cursor keys
- if ((dir = _vm->getKeyDirection()) != 0) {
+ dir = _vm->getKeyDirection();
+ if (dir != 0) {
if (dir & MSK_LEFT)
newX -= IterationSize;
@@ -417,7 +418,7 @@ static void MoveCursor(void) {
if (dir & MSK_DOWN)
newY += IterationSize;
- IterationSize += ITER_ACCELLERATION;
+ IterationSize += ITER_ACCELERATION;
// set new mouse driver position
_vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY)));
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index a638dde2c5..526d72e4a4 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -29,6 +29,7 @@
#include "common/file.h"
#include "tinsel/tinsel.h"
+#include "tinsel/savescn.h" // needed by TinselMetaEngine::listSaves
namespace Tinsel {
@@ -76,13 +77,28 @@ namespace Tinsel {
static const TinselGameDescription gameDescriptions[] = {
- // Note: versions with *.gra files use tinsel v1 (28/2/1995), whereas
- // versions with *.scn files tinsel v2 (7/5/1995)
- // Update: this is not entirely true, there were some versions released
- // with *.gra files and used tinsel v2
+ // The DW1 demo was based on an older revision of the Tinsel engine
+ // than the one used in the released game. We call it Tinsel v0 as
+ // opposed to v1 which was used in the full retail version of DW.
+
+ { // Demo from http://www.adventure-treff.de/specials/dl_demos.php
+ {
+ "dw",
+ "Demo",
+ AD_ENTRY1s("dw.gra", "ce1b57761ba705221bcf70955b827b97", 441192),
+ //AD_ENTRY1s("dw.scn", "ccd72f02183d0e96b6e7d8df9492cda8", 23308),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_DEMO
+ },
+ GID_DW1,
+ 0,
+ GF_DEMO,
+ TINSEL_V0,
+ },
{
- { // This version has *.gra files but uses tinsel v2
+ { // This version has *.gra files
"dw",
"Floppy",
AD_ENTRY1s("dw.gra", "c8808ccd988d603dd35dff42013ae7fd", 781656),
@@ -93,10 +109,34 @@ static const TinselGameDescription gameDescriptions[] = {
GID_DW1,
0,
GF_FLOPPY,
- TINSEL_V2,
+ TINSEL_V1,
+ },
+
+ { // Multilingual floppy with *.gra files.
+ // Note: It contains no english subtitles.
+ // Reported on our forums.
+ {
+ "dw",
+ "Floppy",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ GID_DW1,
+ 0,
+ GF_FLOPPY | GF_USE_4FLAGS,
+ TINSEL_V1,
},
- { // English CD v1. This version has *.gra files but uses tinsel v2
+ { // English CD. This version has *.gra files
{
"dw",
"CD",
@@ -112,35 +152,105 @@ static const TinselGameDescription gameDescriptions[] = {
GID_DW1,
0,
GF_CD,
- TINSEL_V2,
+ TINSEL_V1,
},
- { // English CD v2
+ { // Multilingual CD with english speech and *.gra files.
+ // Note: It contains no english subtitles.
{
"dw",
"CD",
{
- {"dw.scn", 0, "70955425870c7720d6eebed903b2ef41", 776188},
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
{"english.smp", 0, NULL, -1},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
{NULL, 0, NULL, 0}
},
- Common::EN_ANY,
+ Common::FR_FRA,
Common::kPlatformPC,
- Common::ADGF_NO_FLAGS
+ Common::ADGF_DROPLANGUAGE
},
GID_DW1,
0,
- GF_CD | GF_SCNFILES,
- TINSEL_V2,
+ GF_CD | GF_USE_4FLAGS,
+ TINSEL_V1,
+ },
+ {
+ {
+ "dw",
+ "CD",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"english.smp", 0, NULL, -1},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ GID_DW1,
+ 0,
+ GF_CD | GF_USE_4FLAGS,
+ TINSEL_V1,
+ },
+ {
+ {
+ "dw",
+ "CD",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"english.smp", 0, NULL, -1},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ GID_DW1,
+ 0,
+ GF_CD | GF_USE_4FLAGS,
+ TINSEL_V1,
+ },
+ {
+ {
+ "dw",
+ "CD",
+ {
+ {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656},
+ {"english.smp", 0, NULL, -1},
+ {"french.txt", 0, NULL, -1},
+ {"german.txt", 0, NULL, -1},
+ {"italian.txt", 0, NULL, -1},
+ {"spanish.txt", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ GID_DW1,
+ 0,
+ GF_CD | GF_USE_4FLAGS,
+ TINSEL_V1,
},
-#if 0
- { // English Saturn CD
+ { // English CD with SCN files
{
"dw",
"CD",
{
- {"dw.scn", 0, "6803f293c88758057cc685b9437f7637", 382248},
+ {"dw.scn", 0, "70955425870c7720d6eebed903b2ef41", 776188},
{"english.smp", 0, NULL, -1},
{NULL, 0, NULL, 0}
},
@@ -150,26 +260,30 @@ static const TinselGameDescription gameDescriptions[] = {
},
GID_DW1,
0,
- GF_CD,
- TINSEL_V2,
+ GF_CD | GF_SCNFILES,
+ TINSEL_V1,
},
-#endif
- { // Demo from http://www.adventure-treff.de/specials/dl_demos.php
+#if 0
+ { // English Saturn CD. Not (yet?) supported
{
"dw",
- "Demo",
- AD_ENTRY1s("dw.gra", "ce1b57761ba705221bcf70955b827b97", 441192),
- //AD_ENTRY1s("dw.scn", "ccd72f02183d0e96b6e7d8df9492cda8", 23308),
+ "CD",
+ {
+ {"dw.scn", 0, "6803f293c88758057cc685b9437f7637", 382248},
+ {"english.smp", 0, NULL, -1},
+ {NULL, 0, NULL, 0}
+ },
Common::EN_ANY,
Common::kPlatformPC,
- Common::ADGF_DEMO
+ Common::ADGF_NO_FLAGS
},
GID_DW1,
0,
- GF_DEMO,
+ GF_CD,
TINSEL_V1,
},
+#endif
{ // German CD re-release "Neon Edition"
// Note: This release has ENGLISH.TXT (with german content) instead of GERMAN.TXT
@@ -184,29 +298,10 @@ static const TinselGameDescription gameDescriptions[] = {
GID_DW1,
0,
GF_CD | GF_SCNFILES,
- TINSEL_V2,
+ TINSEL_V1,
},
-
- { AD_TABLE_END_MARKER, 0, 0, 0, 0 }
-};
-/**
- * The fallback game descriptor used by the Tinsel engine's fallbackDetector.
- * Contents of this struct are to be overwritten by the fallbackDetector.
- */
-static TinselGameDescription g_fallbackDesc = {
- {
- "",
- "",
- AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
- Common::UNK_LANG,
- Common::kPlatformPC,
- Common::ADGF_NO_FLAGS
- },
- 0,
- 0,
- 0,
- 0,
+ { AD_TABLE_END_MARKER, 0, 0, 0, 0 }
};
} // End of namespace Tinsel
@@ -239,15 +334,42 @@ public:
}
virtual const char *getCopyright() const {
+ // FIXME: Bad copyright string.
+ // Should be something like "Tinsel (C) Psygnosis" or so... ???
return "Tinsel Engine";
}
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
- const Common::ADGameDescription *fallbackDetect(const FSList *fslist) const;
-
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual SaveStateList listSaves(const char *target) const;
};
+bool TinselMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves);
+}
+
+namespace Tinsel {
+extern int getList(Common::SaveFileManager *saveFileMan, const Common::String &target);
+}
+
+SaveStateList TinselMetaEngine::listSaves(const char *target) const {
+ int numStates = Tinsel::getList(g_system->getSavefileManager(), target);
+
+ SaveStateList saveList;
+ for (int i = 0; i < numStates; i++) {
+ SaveStateDescriptor sd(i,
+ Tinsel::ListEntry(i, Tinsel::LE_DESC),
+ Tinsel::ListEntry(i, Tinsel::LE_NAME));
+ // TODO: Also add savedFiles[i].dateTime to the SaveStateDescriptor
+ saveList.push_back(sd);
+ }
+
+ return saveList;
+}
+
+
bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Tinsel::TinselGameDescription *gd = (const Tinsel::TinselGameDescription *)desc;
if (gd) {
@@ -256,21 +378,6 @@ bool TinselMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm
return gd != 0;
}
-const Common::ADGameDescription *TinselMetaEngine::fallbackDetect(const FSList *fslist) const {
- // Set the default values for the fallback descriptor's ADGameDescription part.
- Tinsel::g_fallbackDesc.desc.language = Common::UNK_LANG;
- Tinsel::g_fallbackDesc.desc.platform = Common::kPlatformPC;
- Tinsel::g_fallbackDesc.desc.flags = Common::ADGF_NO_FLAGS;
-
- // Set default values for the fallback descriptor's TinselGameDescription part.
- Tinsel::g_fallbackDesc.gameID = 0;
- Tinsel::g_fallbackDesc.features = 0;
- Tinsel::g_fallbackDesc.version = 0;
-
- //return (const Common::ADGameDescription *)&Tinsel::g_fallbackDesc;
- return NULL;
-}
-
#if PLUGIN_ENABLED_DYNAMIC(TINSEL)
REGISTER_PLUGIN_DYNAMIC(TINSEL, PLUGIN_TYPE_ENGINE, TinselMetaEngine);
#else
diff --git a/engines/tinsel/dw.h b/engines/tinsel/dw.h
index d14dd43fa2..9ceef37858 100644
--- a/engines/tinsel/dw.h
+++ b/engines/tinsel/dw.h
@@ -110,8 +110,11 @@ typedef int HPOLYGON;
// Language for the resource strings
enum LANGUAGE {
- TXT_ENGLISH, TXT_FRENCH, TXT_GERMAN,
- TXT_ITALIAN, TXT_SPANISH
+ TXT_ENGLISH,
+ TXT_FRENCH,
+ TXT_GERMAN,
+ TXT_ITALIAN,
+ TXT_SPANISH
};
} // end of namespace Tinsel
diff --git a/engines/tinsel/inventory.cpp b/engines/tinsel/inventory.cpp
index 2a0f3695c0..d20ada51ac 100644
--- a/engines/tinsel/inventory.cpp
+++ b/engines/tinsel/inventory.cpp
@@ -29,8 +29,6 @@
* And there's still a bit of tidying and commenting to do yet.
*/
-//#define USE_3FLAGS 1
-
#include "tinsel/actors.h"
#include "tinsel/anim.h"
#include "tinsel/background.h"
@@ -370,9 +368,7 @@ enum BFUNC {
NOFUNC, SAVEGAME, LOADGAME, IQUITGAME, CLOSEWIN,
OPENLOAD, OPENSAVE, OPENREST,
OPENSOUND, OPENCONT,
-#ifndef JAPAN
OPENSUBT,
-#endif
OPENQUIT,
INITGAME, MIDIVOL,
CLANG, RLANG
@@ -402,9 +398,7 @@ struct CONFBOX {
#define SIX_RESTART_OPTION 2
#define SIX_SOUND_OPTION 3
#define SIX_CONTROL_OPTION 4
-#ifndef JAPAN
#define SIX_SUBTITLES_OPTION 5
-#endif
#define SIX_QUIT_OPTION 6
#define SIX_RESUME_OPTION 7
#define SIX_LOAD_HEADING 8
@@ -531,9 +525,9 @@ CONFBOX restartBox[] = {
};
#else
CONFBOX soundBox[] = {
- { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 25, MAXMIDIVOL, 2, &volMidi, 0 },
- { SLIDER, NOFUNC, NULL, SIX_SVOL_SLIDER, 142, 25+40, MAXSAMPVOL, 2, &volSound, 0 },
- { SLIDER, NOFUNC, NULL, SIX_VVOL_SLIDER, 142, 25+2*40, MAXSAMPVOL, 2, &volVoice, 0 }
+ { SLIDER, MIDIVOL, NULL, SIX_MVOL_SLIDER, 142, 25, Audio::Mixer::kMaxChannelVolume, 2, &volMidi, 0 },
+ { SLIDER, NOFUNC, NULL, SIX_SVOL_SLIDER, 142, 25+40, Audio::Mixer::kMaxChannelVolume, 2, &volSound, 0 },
+ { SLIDER, NOFUNC, NULL, SIX_VVOL_SLIDER, 142, 25+2*40, Audio::Mixer::kMaxChannelVolume, 2, &volVoice, 0 }
};
#endif
@@ -568,41 +562,60 @@ CONFBOX controlBox[] = {
/*-------------------------------------------------------------*\
-| This is the subtitles 'menu'. |
+| This is the subtitles 'menu'. |
\*-------------------------------------------------------------*/
-#ifndef JAPAN
CONFBOX subtitlesBox[] = {
-#ifdef USE_5FLAGS
+ { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 },
+ { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 },
+
+};
+
+CONFBOX subtitlesBox3Flags[] = {
+
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR },
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR },
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP },
+
+ { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 },
+ { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 },
+
+ { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 },
+ { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 }
+
+};
+
+CONFBOX subtitlesBox4Flags[] = {
+
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR },
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR },
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT },
+ { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP },
+
+ { SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 },
+ { TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 },
+
+ { ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 },
+ { AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 }
+
+};
+
+CONFBOX subtitlesBox5Flags[] = {
+
{ FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 100, 56, 32, NULL, FIX_UK },
{ FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 100, 56, 32, NULL, FIX_FR },
{ FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 100, 56, 32, NULL, FIX_GR },
{ FRGROUP, NOFUNC, NULL, USE_POINTER, 50, 137, 56, 32, NULL, FIX_IT },
{ FRGROUP, NOFUNC, NULL, USE_POINTER, 120, 137, 56, 32, NULL, FIX_SP },
-#endif
-#ifdef USE_4FLAGS
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 20, 100, 56, 32, NULL, FIX_FR },
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 108, 100, 56, 32, NULL, FIX_GR },
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 64, 137, 56, 32, NULL, FIX_IT },
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 152, 137, 56, 32, NULL, FIX_SP },
-#endif
-#ifdef USE_3FLAGS
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 15, 118, 56, 32, NULL, FIX_FR },
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 85, 118, 56, 32, NULL, FIX_GR },
- { FRGROUP, NOFUNC, NULL, USE_POINTER, 155, 118, 56, 32, NULL, FIX_SP },
-#endif
{ SLIDER, NOFUNC, NULL, SIX_TSPEED_SLIDER, 142, 20, 100, 2, &speedText, 0 },
{ TOGGLE, NOFUNC, NULL, SIX_STITLE_TOGGLE, 142, 20+40, 23, 19, &bSubtitles, 0 },
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
{ ARSGBUT, CLANG, NULL, USE_POINTER, 230, 110, 23, 19, NULL, IX_TICK1 },
{ AAGBUT, RLANG, NULL, USE_POINTER, 230, 140, 23, 19, NULL, IX_CROSS1 }
-#endif
};
-#endif
/*-------------------------------------------------------------*\
@@ -610,7 +623,7 @@ CONFBOX subtitlesBox[] = {
\*-------------------------------------------------------------*/
CONFBOX quitBox[] = {
-#ifdef JAPAN
+#ifdef g
{ AAGBUT, IQUITGAME, NULL, USE_POINTER,70, 44, 23, 19, NULL, IX_TICK1 },
{ AAGBUT, CLOSEWIN, NULL, USE_POINTER, 30, 44, 23, 19, NULL, IX_CROSS1 }
#else
@@ -652,13 +665,9 @@ CONFINIT ciSound = { 10, 5, 20, 16, false, soundBox, ARRAYSIZE(soundBox), NO_HEA
#else
CONFINIT ciControl = { 10, 5, 20, 16, false, controlBox, ARRAYSIZE(controlBox), NO_HEADING };
#endif
-#ifndef JAPAN
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
-CONFINIT ciSubtitles = { 10, 6, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING };
-#else
+
CONFINIT ciSubtitles = { 10, 3, 20, 16, false, subtitlesBox, ARRAYSIZE(subtitlesBox), NO_HEADING };
-#endif
-#endif
+
CONFINIT ciQuit = { 4, 2, 98, 53, false, quitBox, ARRAYSIZE(quitBox), SIX_QUIT_HEADING };
CONFINIT ciTopWin = { 6, 5, 72, 23, false, topwinBox, 0, NO_HEADING };
@@ -762,45 +771,39 @@ static void ConfActionSpecial(int i);
-#ifndef JAPAN
bool LanguageChange(void) {
- LANGUAGE nLang;
-
-#ifdef USE_3FLAGS
- // VERY quick dodgy bodge
- if (cd.selBox == 0)
- nLang = TXT_FRENCH;
- else if (cd.selBox == 1)
- nLang = TXT_GERMAN;
- else
- nLang = TXT_SPANISH;
- if (nLang != language) {
-#elif defined(USE_4FLAGS)
- nLang = (LANGUAGE)(cd.selBox + 1);
- if (nLang != language) {
-#else
- if (cd.selBox != language) {
+ LANGUAGE nLang = TXT_ENGLISH;
+
+ if (_vm->getFeatures() & GF_USE_3FLAGS) {
+ // VERY quick dodgy bodge
+ if (cd.selBox == 0)
+ nLang = TXT_FRENCH; // = 1
+ else if (cd.selBox == 1)
+ nLang = TXT_GERMAN; // = 2
+ else
+ nLang = TXT_SPANISH; // = 4
+ } else if (_vm->getFeatures() & GF_USE_4FLAGS) {
+ nLang = (LANGUAGE)(cd.selBox + 1);
+ } else if (_vm->getFeatures() & GF_USE_5FLAGS) {
nLang = (LANGUAGE)cd.selBox;
-#endif
+ }
+
+ if (nLang != g_language) {
KillInventory();
ChangeLanguage(nLang);
- language = nLang;
+ g_language = nLang;
return true;
- }
- else
+ } else
return false;
}
-#endif
/**************************************************************************/
/******************** Some miscellaneous functions ************************/
/**************************************************************************/
-/*---------------------------------------------------------------------*\
-| DumpIconArray()/DumpDobjArray()/DumpObjArray() |
-|-----------------------------------------------------------------------|
-| Delete all the objects in iconArray[]/DobjArray[]/objArray[] |
-\*---------------------------------------------------------------------*/
+/**
+ * Delete all the objects in iconArray[]
+ */
static void DumpIconArray(void){
for (int i = 0; i < MAX_ICONS; i++) {
if (iconArray[i] != NULL) {
@@ -813,7 +816,6 @@ static void DumpIconArray(void){
/**
* Delete all the objects in DobjArray[]
*/
-
static void DumpDobjArray(void) {
for (int i = 0; i < MAX_WCOMP; i++) {
if (DobjArray[i] != NULL) {
@@ -826,7 +828,6 @@ static void DumpDobjArray(void) {
/**
* Delete all the objects in objArray[]
*/
-
static void DumpObjArray(void) {
for (int i = 0; i < MAX_WCOMP; i++) {
if (objArray[i] != NULL) {
@@ -886,7 +887,6 @@ bool IsInInventory(int object, int invnum) {
/**
* Returns which item is held (INV_NOICON (-1) if none)
*/
-
int WhichItemHeld(void) {
return HeldItem;
}
@@ -895,7 +895,6 @@ int WhichItemHeld(void) {
* Called from the cursor module when it re-initialises (at the start of
* a new scene). For if we are holding something at scene-change time.
*/
-
void InventoryIconCursor(void) {
INV_OBJECT *invObj;
@@ -908,7 +907,6 @@ void InventoryIconCursor(void) {
/**
* Returns TRUE if the inventory is active.
*/
-
bool InventoryActive(void) {
return (InventoryState == ACTIVE_INV);
}
@@ -1214,8 +1212,8 @@ void Select(int i, bool force) {
break;
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
case FRGROUP:
+ assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));
iconArray[HL2] = RectangleObject(BackPal(), COL_HILIGHT, cd.Box[i].w+6, cd.Box[i].h+6);
MultiInsertObject(GetPlayfieldList(FIELD_STATUS), iconArray[HL2]);
MultiSetAniXY(iconArray[HL2],
@@ -1224,7 +1222,7 @@ void Select(int i, bool force) {
MultiSetZPosition(iconArray[HL2], Z_INV_BRECT+1);
break;
-#endif
+
default:
break;
}
@@ -1276,7 +1274,6 @@ void DropItem(int item) {
* Stick the item into an inventory list (ItemOrder[]), and hold the
* item if requested.
*/
-
void AddToInventory(int invno, int icon, bool hold) {
int i;
bool bOpen;
@@ -1407,12 +1404,12 @@ int InvArea(int x, int y) {
int RightX = MultiRightmost(RectObject) + 1;
int BottomY = MultiLowest(RectObject) + 1;
-// Outside the whole rectangle?
+ // Outside the whole rectangle?
if (x <= LeftX - EXTRA || x > RightX + EXTRA
|| y <= TopY - EXTRA || y > BottomY + EXTRA)
return I_NOTIN;
-// The bottom line
+ // The bottom line
if (y > BottomY - 2 - EXTRA) { // Below top of bottom line?
if (x <= LeftX + 2 + EXTRA)
return I_BLEFT; // Bottom left corner
@@ -1422,7 +1419,7 @@ int InvArea(int x, int y) {
return I_BOTTOM; // Just plain bottom
}
-// The top line
+ // The top line
if (y <= TopY + 2 + EXTRA) { // Above bottom of top line?
if (x <= LeftX + 2 + EXTRA)
return I_TLEFT; // Top left corner
@@ -1432,24 +1429,24 @@ int InvArea(int x, int y) {
return I_TOP; // Just plain top
}
-// Sides
+ // Sides
if (x <= LeftX + 2 + EXTRA) // Left of right of left side?
return I_LEFT;
else if (x > RightX - 2 - EXTRA) // Right of left of right side?
return I_RIGHT;
-// From here down still needs fixing up properly
-/*
-* In the move area?
-*/
+ // From here down still needs fixing up properly
+ /*
+ * In the move area?
+ */
if (ino != INV_CONF
&& x >= LeftX + M_SW - 2 && x <= RightX - M_SW + 3 &&
y >= TopY + M_TH - 2 && y < TopY + M_TBB + 2)
return I_MOVE;
-/*
-* Scroll bits
-*/
+ /*
+ * Scroll bits
+ */
if (ino == INV_CONF && cd.bExtraWin) {
} else {
if (x > RightX - M_IAL + 3 && x <= RightX - M_IAR + 1) {
@@ -1476,7 +1473,6 @@ int InvArea(int x, int y) {
* Returns the id of the icon displayed under the given position.
* Also return co-ordinates of items tag display position, if requested.
*/
-
int InvItem(int *x, int *y, bool update) {
int itop, ileft;
int row, col;
@@ -1510,7 +1506,6 @@ int InvItem(int *x, int *y, bool update) {
/**
* Returns the id of the icon displayed under the given position.
*/
-
int InvItemId(int x, int y) {
int itop, ileft;
int row, col;
@@ -1539,21 +1534,21 @@ int InvItemId(int x, int y) {
return INV_NOICON;
}
-/*---------------------------------------------------------------------*\
-| WhichInvBox() |
-|-----------------------------------------------------------------------|
-| Finds which box the cursor is in. |
-\*---------------------------------------------------------------------*/
-#define MD_YSLIDTOP 7
-#define MD_YSLIDBOT 18
-#define MD_YBUTTOP 9
-#define MD_YBUTBOT 16
-#define MD_XLBUTL 1
-#define MD_XLBUTR 10
-#define MD_XRBUTL 105
-#define MD_XRBUTR 114
-
+/**
+ * Finds which box the cursor is in.
+ */
static int WhichInvBox(int curX, int curY, bool bSlides) {
+ enum {
+ MD_YSLIDTOP = 7,
+ MD_YSLIDBOT = 18,
+ MD_YBUTTOP = 9,
+ MD_YBUTBOT = 16,
+ MD_XLBUTL = 1,
+ MD_XLBUTR = 10,
+ MD_XRBUTL = 105,
+ MD_XRBUTR = 114
+ };
+
if (bSlides) {
for (int i = 0; i < numMdSlides; i++) {
if (curY > MultiHighest(mdSlides[i].obj) && curY < MultiLowest(mdSlides[i].obj)
@@ -1841,7 +1836,6 @@ void InvLabels(bool InBody, int aniX, int aniY) {
* It seems to set up slideStuff[], an array of possible first-displayed
* icons set against the matching y-positions of the slider.
*/
-
void AdjustTop(void) {
int tMissing, bMissing, nMissing;
int nslideY;
@@ -1904,7 +1898,6 @@ void AdjustTop(void) {
/**
* Insert an inventory icon object onto the display list.
*/
-
OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) {
INV_OBJECT *invObj; // Icon data
const MULTI_INIT *pmi; // Its INIT structure - from the reel
@@ -1929,7 +1922,6 @@ OBJECT *AddInvObject(int num, const FREEL **pfreel, const FILM **pfilm) {
/**
* Create display objects for the displayed icons in an inventory window.
*/
-
void FillInInventory(void) {
int Index; // Index into ItemOrder[]
int n = 0; // index into iconArray[]
@@ -2010,7 +2002,6 @@ void AddBackground(OBJECT **rect, OBJECT **title, int extraH, int extraV, int te
/**
* Insert a part of the inventory window frame onto the display list.
*/
-
static OBJECT *AddObject(const FREEL *pfreel, int num) {
const MULTI_INIT *pmi; // Get the MULTI_INIT structure
IMAGE *pim;
@@ -2043,7 +2034,6 @@ static OBJECT *AddObject(const FREEL *pfreel, int num) {
/**
* Display the scroll bar slider.
*/
-
void AddSlider(OBJECT **slide, const FILM *pfilm) {
SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1);
MultiSetAniXY(*slide, MultiRightmost(RectObject)-M_SXOFF+2, InvD[ino].inventoryY + slideY);
@@ -2062,7 +2052,6 @@ enum {
/**
* Display a box with some text in it.
*/
-
void AddBox(int *pi, int i) {
int x = InvD[ino].inventoryX + cd.Box[i].xpos;
int y = InvD[ino].inventoryY + cd.Box[i].ypos;
@@ -2126,8 +2115,8 @@ void AddBox(int *pi, int i) {
break;
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
case FRGROUP:
+ assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));
assert(flagFilm != 0); // Language flags not declared!
pfilm = (const FILM *)LockMem(flagFilm);
@@ -2141,7 +2130,7 @@ void AddBox(int *pi, int i) {
*pi += 1;
break;
-#endif
+
case FLIP:
pfilm = (const FILM *)LockMem(winPartsf);
@@ -2234,7 +2223,6 @@ static void AddBoxes(bool posnSlide) {
/**
* Display the scroll bar slider.
*/
-
void AddEWSlider(OBJECT **slide, const FILM *pfilm) {
SlideObject = *slide = AddObject(&pfilm->reels[IX_SLIDE], -1);
MultiSetAniXY(*slide, InvD[ino].inventoryX + 24 + 127, slideY);
@@ -2244,7 +2232,6 @@ void AddEWSlider(OBJECT **slide, const FILM *pfilm) {
/**
* AddExtraWindow
*/
-
int AddExtraWindow(int x, int y, OBJECT **retObj) {
int n = 0;
const FILM *pfilm;
@@ -2479,7 +2466,7 @@ void ConstructInventory(InventoryType filling) {
OBJECT **rect, **title;
-// Draw background, slider and icons
+ // Draw background, slider and icons
if (filling == FULL) {
rect = &retObj[n++];
title = &retObj[n++];
@@ -2495,8 +2482,7 @@ void ConstructInventory(InventoryType filling) {
}
FillInInventory();
- }
- else if (filling == CONF) {
+ } else if (filling == CONF) {
rect = &retObj[n++];
title = &retObj[n++];
@@ -2800,7 +2786,6 @@ bool convHid(void) {
/**
* Start up an inventory window.
*/
-
void PopUpInventory(int invno) {
assert((invno == INV_1 || invno == INV_2 || invno == INV_CONV || invno == INV_CONF)); // Trying to open illegal inventory
@@ -2849,7 +2834,6 @@ void SetConfGlobals(CONFINIT *ci) {
/**
* PopupConf
*/
-
void PopUpConf(CONFTYPE type) {
int curX, curY;
@@ -2903,11 +2887,27 @@ void PopUpConf(CONFTYPE type) {
SetConfGlobals(&ciSound);
break;
-#ifndef JAPAN
case SUBT:
+ if (_vm->getFeatures() & GF_USE_3FLAGS) {
+ ciSubtitles.v = 6;
+ ciSubtitles.Box = subtitlesBox3Flags;
+ ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox3Flags);
+ } else if (_vm->getFeatures() & GF_USE_4FLAGS) {
+ ciSubtitles.v = 6;
+ ciSubtitles.Box = subtitlesBox4Flags;
+ ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags);
+ } else if (_vm->getFeatures() & GF_USE_5FLAGS) {
+ ciSubtitles.v = 6;
+ ciSubtitles.Box = subtitlesBox4Flags;
+ ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox4Flags);
+ } else {
+ ciSubtitles.v = 3;
+ ciSubtitles.Box = subtitlesBox;
+ ciSubtitles.NumBoxes = ARRAYSIZE(subtitlesBox);
+ }
+
SetConfGlobals(&ciSubtitles);
break;
-#endif
case TOPWIN:
SetConfGlobals(&ciTopWin);
@@ -2927,25 +2927,21 @@ void PopUpConf(CONFTYPE type) {
if (type == SAVE || type == LOAD)
Select(0, false);
-#ifndef JAPAN
-#if !defined(USE_3FLAGS) || !defined(USE_4FLAGS) || !defined(USE_5FLAGS)
else if (type == SUBT) {
-#ifdef USE_3FLAGS
- // VERY quick dirty bodges
- if (language == TXT_FRENCH)
- Select(0, false);
- else if (language == TXT_GERMAN)
- Select(1, false);
- else
- Select(2, false);
-#elif defined(USE_4FLAGS)
- Select(language-1, false);
-#else
- Select(language, false);
-#endif
+ if (_vm->getFeatures() & GF_USE_3FLAGS) {
+ // VERY quick dirty bodges
+ if (g_language == TXT_FRENCH)
+ Select(0, false);
+ else if (g_language == TXT_GERMAN)
+ Select(1, false);
+ else
+ Select(2, false);
+ } else if (_vm->getFeatures() & GF_USE_4FLAGS) {
+ Select(g_language-1, false);
+ } else if (_vm->getFeatures() & GF_USE_5FLAGS) {
+ Select(g_language, false);
+ }
}
-#endif
-#endif // JAPAN
GetCursorXY(&curX, &curY, false);
InvCursor(IC_AREA, curX, curY);
@@ -2954,7 +2950,6 @@ void PopUpConf(CONFTYPE type) {
/**
* Close down an inventory window.
*/
-
void KillInventory(void) {
if (objArray[0] != NULL) {
DumpObjArray();
@@ -2976,6 +2971,9 @@ void KillInventory(void) {
if (bOpenConf) {
bOpenConf = false;
PopUpConf(OPTION);
+
+ // Write config changes
+ WriteConfig();
} else if (ino == INV_CONF)
InventoryIconCursor();
}
@@ -3073,7 +3071,7 @@ void InventoryProcess(CORO_PARAM, const void *) {
InvLoadGame();
break;
case IQUITGAME:
- _vm->quitFlag = true;
+ _vm->quitGame();
break;
case CLOSEWIN:
KillInventory();
@@ -3098,12 +3096,10 @@ void InventoryProcess(CORO_PARAM, const void *) {
KillInventory();
PopUpConf(CONTROLS);
break;
- #ifndef JAPAN
case OPENSUBT:
KillInventory();
PopUpConf(SUBT);
break;
- #endif
case OPENQUIT:
KillInventory();
PopUpConf(QUIT);
@@ -3112,7 +3108,6 @@ void InventoryProcess(CORO_PARAM, const void *) {
KillInventory();
bRestart = true;
break;
- #if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
case CLANG:
if (!LanguageChange())
KillInventory();
@@ -3120,7 +3115,6 @@ void InventoryProcess(CORO_PARAM, const void *) {
case RLANG:
KillInventory();
break;
- #endif
default:
break;
}
@@ -3344,10 +3338,8 @@ static void SlideMSlider(int x, SSFN fn) {
case S_END: // End of a drag on the slider
AddBoxes(false); // Might change position slightly
-#ifndef JAPAN
if (ino == INV_CONF && cd.Box == subtitlesBox)
- Select(language, false);
-#endif
+ Select(g_language, false);
break;
}
}
@@ -3780,8 +3772,8 @@ void ConfAction(int i, bool dbl) {
}
break;
-#if defined(USE_3FLAGS) || defined(USE_4FLAGS) || defined(USE_5FLAGS)
case FRGROUP:
+ assert((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS));
if (dbl) {
Select(i, false);
LanguageChange();
@@ -3789,7 +3781,6 @@ void ConfAction(int i, bool dbl) {
Select(i, false);
}
break;
-#endif
case AAGBUT:
case ARSGBUT:
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 7d4efd8079..d165ba0a10 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -263,7 +263,7 @@ int GetMidiVolume() {
* @param vol New volume - 0..MAXMIDIVOL
*/
void SetMidiVolume(int vol) {
- assert(vol >= 0 && vol <= MAXMIDIVOL);
+ assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
if (vol == 0 && volMidi == 0) {
// Nothing to do
@@ -343,10 +343,6 @@ MusicPlayer::~MusicPlayer() {
}
void MusicPlayer::setVolume(int volume) {
- Common::StackLock lock(_mutex);
-
- // FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range?
- volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255);
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
if (_masterVolume == volume)
@@ -354,6 +350,8 @@ void MusicPlayer::setVolume(int volume) {
_masterVolume = volume;
+ Common::StackLock lock(_mutex);
+
for (int i = 0; i < 16; ++i) {
if (_channel[i]) {
_channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h
index 80456e2a76..3d647f95bf 100644
--- a/engines/tinsel/music.h
+++ b/engines/tinsel/music.h
@@ -34,8 +34,6 @@
namespace Tinsel {
-#define MAXMIDIVOL 127
-
bool PlayMidiSequence( // Plays the specified MIDI sequence through the sound driver
uint32 dwFileOffset, // handle of MIDI sequence data
bool bLoop); // Whether to loop the sequence
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 1a6cc1202a..acdaf6c0bb 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -246,16 +246,11 @@ static char *NewName(void) {
* Store the file details, ordered by time, in savedFiles[] and return
* the number of files found).
*/
-int getList(void) {
- // No change since last call?
- // TODO/FIXME: Just always reload this data? Be careful about slow downs!!!
- if (!NeedLoad)
- return numSfiles;
-
+int getList(Common::SaveFileManager *saveFileMan, const Common::String &target) {
int i;
- const Common::String pattern = _vm->getSavegamePattern();
- Common::StringList files = _vm->getSaveFileMan()->listSavefiles(pattern.c_str());
+ const Common::String pattern = target + ".???";
+ Common::StringList files = saveFileMan->listSavefiles(pattern.c_str());
numSfiles = 0;
@@ -264,7 +259,7 @@ int getList(void) {
break;
const Common::String &fname = *file;
- Common::InSaveFile *f = _vm->getSaveFileMan()->openForLoading(fname.c_str());
+ Common::InSaveFile *f = saveFileMan->openForLoading(fname.c_str());
if (f == NULL) {
continue;
}
@@ -304,6 +299,15 @@ int getList(void) {
return numSfiles;
}
+int getList(void) {
+ // No change since last call?
+ // TODO/FIXME: Just always reload this data? Be careful about slow downs!!!
+ if (!NeedLoad)
+ return numSfiles;
+
+ return getList(_vm->getSaveFileMan(), _vm->getTargetName());
+}
+
char *ListEntry(int i, letype which) {
if (i == -1)
diff --git a/engines/tinsel/scn.cpp b/engines/tinsel/scn.cpp
index b14b1c5962..8639979b41 100644
--- a/engines/tinsel/scn.cpp
+++ b/engines/tinsel/scn.cpp
@@ -50,7 +50,7 @@ byte *FindChunk(SCNHANDLE handle, uint32 chunk) {
// V1 chunk types can be found by substracting 2 from the
// chunk type. Note that CHUNK_STRING and CHUNK_BITMAP are
// the same in V1 and V2
- if (_vm->getVersion() == TINSEL_V1 &&
+ if (_vm->getVersion() == TINSEL_V0 &&
chunk != CHUNK_STRING && chunk != CHUNK_BITMAP)
chunk -= 0x2L;
diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp
index e2a24dbd47..e37c80ec61 100644
--- a/engines/tinsel/sound.cpp
+++ b/engines/tinsel/sound.cpp
@@ -74,7 +74,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
assert(id > 0 && id < _sampleIndexLen);
// get file offset for this sample
- uint32 dwSampleIndex = _sampleIndex[id];
+ int32 dwSampleIndex = _sampleIndex[id];
// move to correct position in the sample file
_sampleStream.seek(dwSampleIndex);
@@ -166,7 +166,7 @@ void SoundManager::openSampleFiles(void) {
if (_sampleIndex == NULL) {
// allocate a buffer for the indices
- _sampleIndex = (uint32 *)malloc(_sampleIndexLen);
+ _sampleIndex = (int32 *)malloc(_sampleIndexLen);
// make sure memory allocated
if (_sampleIndex == NULL) {
diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h
index 56618eeb8e..330409cf59 100644
--- a/engines/tinsel/sound.h
+++ b/engines/tinsel/sound.h
@@ -37,7 +37,6 @@
namespace Tinsel {
-#define MAXSAMPVOL 127
/*----------------------------------------------------------------------*\
|* Function Prototypes *|
@@ -52,7 +51,7 @@ protected:
Audio::SoundHandle _handle;
/** Sample index buffer and number of entries */
- uint32 *_sampleIndex;
+ int32 *_sampleIndex;
/** Number of entries in the sample index */
long _sampleIndexLen;
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index e8364e20dd..07c1b22b2a 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -1271,7 +1271,7 @@ void printtag(HPOLYGON hp, SCNHANDLE text) {
void quitgame(void) {
stopmidi();
stopsample();
- _vm->quitFlag = true;
+ _vm->quitGame();
}
/**
@@ -1991,7 +1991,6 @@ void topplay(CORO_PARAM, SCNHANDLE film, int x, int y, int complete, int actorid
/**
* Open or close the 'top window'
*/
-
void topwindow(int bpos) {
assert(bpos == TW_START || bpos == TW_END);
@@ -2010,7 +2009,6 @@ void topwindow(int bpos) {
/**
* unhookscene
*/
-
void unhookscene(void) {
UnHookScene();
}
@@ -2018,7 +2016,6 @@ void unhookscene(void) {
/**
* Un-define an actor as tagged.
*/
-
void untagactor(int actor) {
UnTagActor(actor);
}
@@ -2026,14 +2023,12 @@ void untagactor(int actor) {
/**
* vibrate
*/
-
void vibrate(void) {
}
/**
* waitframe(int actor, int frameNumber)
*/
-
void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEvent) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -2056,7 +2051,6 @@ void waitframe(CORO_PARAM, int actor, int frameNumber, bool escOn, int myescEven
/**
* Return when a key pressed or button pushed.
*/
-
void waitkey(CORO_PARAM, bool escOn, int myescEvent) {
CORO_BEGIN_CONTEXT;
int startEvent;
@@ -2104,7 +2098,6 @@ void waitkey(CORO_PARAM, bool escOn, int myescEvent) {
/**
* Pause for requested time.
*/
-
void waittime(CORO_PARAM, int time, bool frame, bool escOn, int myescEvent) {
CORO_BEGIN_CONTEXT;
int time;
@@ -2261,7 +2254,6 @@ void walkingactor(uint32 id, SCNHANDLE *rp) {
* Walk a moving actor towards the polygon's tag, but return when the
* actor enters the polygon.
*/
-
void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) {
// COROUTINE
CORO_BEGIN_CONTEXT;
@@ -2309,7 +2301,6 @@ void walkpoly(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, in
/**
* walktag(actor, reel, hold)
*/
-
void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int myescEvent) {
// COROUTINE
CORO_BEGIN_CONTEXT;
@@ -2385,7 +2376,6 @@ void walktag(CORO_PARAM, int actor, SCNHANDLE film, HPOLYGON hp, bool escOn, int
/**
* whichinventory
*/
-
int whichinventory(void) {
return WhichInventoryOpen();
}
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 1f56385283..7fb949704a 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -206,13 +206,16 @@ void KeyboardProcess(CORO_PARAM, const void *) {
{
int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0;
int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset;
- if ((language == TXT_GERMAN) &&
+#if 0 // FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922).
+ if ((g_language == TXT_GERMAN) &&
((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) {
// Skip to title screen
// It seems the German CD version uses scenes 25,26,27,17 for the intro,
// instead of 13,14,15,11; also, the title screen is 11 instead of 10
SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
- } else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
+ } else
+#endif
+ if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) {
// Skip to title screen
SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT);
} else {
@@ -622,11 +625,11 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
//bool adlib = (midiDriver == MD_ADLIB);
- MidiDriver *driver = MidiDriver::createMidi(midiDriver);
+ _driver = MidiDriver::createMidi(midiDriver);
if (native_mt32)
- driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _music = new MusicPlayer(driver);
+ _music = new MusicPlayer(_driver);
//_music->setNativeMT32(native_mt32);
//_music->setAdlib(adlib);
@@ -638,13 +641,14 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
_mousePos.y = 0;
_keyHandler = NULL;
_dosPlayerDir = 0;
- quitFlag = false;
}
TinselEngine::~TinselEngine() {
delete _sound;
delete _music;
delete _console;
+ delete _driver;
+ _screenSurface.free();
FreeSs();
FreeTextBuffer();
FreeHandleTable();
@@ -678,6 +682,8 @@ int TinselEngine::init() {
#if 1
// FIXME: The following is taken from RestartGame().
// It may have to be adjusted a bit
+ CountOut = 1;
+
RebootCursor();
RebootDeadTags();
RebootMovers();
@@ -692,25 +698,8 @@ int TinselEngine::init() {
// TODO: More stuff from dos_main.c may have to be added here
- // Set language - we'll be clever here and use the ScummVM language setting
- language = TXT_ENGLISH;
- switch (getLanguage()) {
- case Common::FR_FRA:
- language = TXT_FRENCH;
- break;
- case Common::DE_DEU:
- language = TXT_GERMAN;
- break;
- case Common::IT_ITA:
- language = TXT_ITALIAN;
- break;
- case Common::ES_ESP:
- language = TXT_SPANISH;
- break;
- default:
- language = TXT_ENGLISH;
- }
- ChangeLanguage(language);
+ // load in text strings
+ ChangeLanguage(g_language);
// load in graphics info
SetupHandleTable();
@@ -721,10 +710,6 @@ int TinselEngine::init() {
return 0;
}
-Common::String TinselEngine::getSavegamePattern() const {
- return _targetName + ".???";
-}
-
Common::String TinselEngine::getSavegameFilename(int16 saveNum) const {
char filename[256];
snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum);
@@ -755,7 +740,7 @@ int TinselEngine::go() {
// Foreground loop
- while (!quitFlag) {
+ while (!quit()) {
assert(_console);
if (_console->isAttached())
_console->onFrame();
@@ -819,10 +804,6 @@ bool TinselEngine::pollEvent() {
// Handle the various kind of events
switch (event.type) {
- case Common::EVENT_QUIT:
- quitFlag = true;
- break;
-
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index 9ffadfe8c1..9820be7ddd 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -55,12 +55,19 @@ enum TinselGameFeatures {
GF_DEMO = 1 << 0,
GF_CD = 1 << 1,
GF_FLOPPY = 1 << 2,
- GF_SCNFILES = 1 << 3
+ GF_SCNFILES = 1 << 3,
+
+ // The GF_USE_?FLAGS values specify how many country flags are displayed
+ // in the subtitles options dialog.
+ // None of these defined -> 1 language, in ENGLISH.TXT
+ GF_USE_3FLAGS = 1 << 4, // French, German, Spanish
+ GF_USE_4FLAGS = 1 << 5, // French, German, Spanish, Italian
+ GF_USE_5FLAGS = 1 << 6 // All 5 flags
};
enum TinselEngineVersion {
- TINSEL_V1 = 1 << 0,
- TINSEL_V2 = 1 << 1
+ TINSEL_V0 = 0, // Used in the DW1 demo only
+ TINSEL_V1 = 1
};
struct TinselGameDescription;
@@ -72,7 +79,7 @@ enum TinselKeyDirection {
typedef bool (*KEYFPTR)(const Common::KeyState &);
-class TinselEngine : public ::Engine {
+class TinselEngine : public Engine {
int _gameId;
Common::KeyState _keyPressed;
Common::RandomSource _random;
@@ -100,8 +107,8 @@ public:
Common::Language getLanguage() const;
uint16 getVersion() const;
Common::Platform getPlatform() const;
- bool quitFlag;
+ MidiDriver *_driver;
SoundManager *_sound;
MusicPlayer *_music;
@@ -120,7 +127,6 @@ private:
public:
const Common::String getTargetName() const { return _targetName; }
- Common::String getSavegamePattern() const;
Common::String getSavegameFilename(int16 saveNum) const;
Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; }
Graphics::Surface &screen() { return _screenSurface; }
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index d2798d7060..bbc605ba46 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -25,6 +25,7 @@
#include "common/config-manager.h"
#include "common/advancedDetector.h"
+#include "common/savefile.h"
#include "base/plugins.h"
@@ -135,9 +136,20 @@ public:
return "Touche: The Adventures of the 5th Musketeer (C) Clipper Software";
}
+ virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
};
+bool ToucheMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDirectLoad) ||
+ (f == kSupportsDeleteSave);
+}
+
bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Common::ADGameDescription *gd = desc;
if (gd) {
@@ -146,6 +158,67 @@ bool ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const Comm
return gd != 0;
}
+SaveStateList ToucheMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ char saveDesc[Touche::kGameStateDescriptionLen];
+ Common::String pattern = target;
+ pattern += ".?";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last digit of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 1);
+
+ if (slotNum >= 0 && slotNum <= 9) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ in->readUint16LE();
+ in->readUint16LE();
+ in->read(saveDesc, Touche::kGameStateDescriptionLen);
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ delete in;
+ }
+ }
+ }
+
+ pattern += "?";
+
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 2 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 2);
+
+ if (slotNum >= 10 && slotNum <= 99) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ in->readUint16LE();
+ in->readUint16LE();
+ in->read(saveDesc, Touche::kGameStateDescriptionLen);
+ saveList.push_back(SaveStateDescriptor(slotNum, Common::String(saveDesc), *file));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+void ToucheMetaEngine::removeSaveState(const char *target, int slot) const {
+ char extension[5];
+ snprintf(extension, sizeof(extension), ".%d", slot);
+
+ Common::String filename = target;
+ filename += extension;
+
+ g_system->getSavefileManager()->removeSavefile(filename.c_str());
+}
+
#if PLUGIN_ENABLED_DYNAMIC(TOUCHE)
REGISTER_PLUGIN_DYNAMIC(TOUCHE, PLUGIN_TYPE_ENGINE, ToucheMetaEngine);
#else
diff --git a/engines/touche/graphics.cpp b/engines/touche/graphics.cpp
index 999aa8005c..ab711beba0 100644
--- a/engines/touche/graphics.cpp
+++ b/engines/touche/graphics.cpp
@@ -76,10 +76,13 @@ int Graphics::getCharWidth16(uint8 chr) {
return chrData[2];
}
-void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str) {
+void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax) {
while (*str) {
uint8 chr = (uint8)*str++;
x += drawChar16(dst, dstPitch, chr, x, y, color);
+ if (xmax != 0 && x > xmax) {
+ break;
+ }
}
}
diff --git a/engines/touche/graphics.h b/engines/touche/graphics.h
index 6b4072d896..9c928f983c 100644
--- a/engines/touche/graphics.h
+++ b/engines/touche/graphics.h
@@ -40,7 +40,7 @@ public:
static void setupFont(Common::Language language);
static int getStringWidth16(const char *str);
static int getCharWidth16(uint8 chr);
- static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str);
+ static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax = 0);
static int drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color);
static void fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color);
static void drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2);
diff --git a/engines/touche/menu.cpp b/engines/touche/menu.cpp
index 6d2d90a572..82490fca38 100644
--- a/engines/touche/menu.cpp
+++ b/engines/touche/menu.cpp
@@ -297,7 +297,7 @@ void ToucheEngine::handleMenuAction(void *menu, int actionId) {
menuData->quit = true;
break;
case kActionQuitGame:
- _flagsTable[611] = 1;
+ quitGame();
menuData->quit = true;
break;
case kActionTextOnly:
@@ -395,10 +395,10 @@ void ToucheEngine::handleOptions(int forceDisplay) {
while (_eventMan->pollEvent(event)) {
const Button *button = 0;
switch (event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
menuData.quit = true;
menuData.exit = true;
- _flagsTable[611] = 1;
break;
case Common::EVENT_LBUTTONDOWN:
button = menuData.findButtonUnderCursor(event.mouse.x, event.mouse.y);
@@ -433,8 +433,9 @@ void ToucheEngine::handleOptions(int forceDisplay) {
_system->delayMillis(10);
}
_fullRedrawCounter = 2;
- if (!menuData.exit && _flagsTable[611] != 0) {
- _flagsTable[611] = displayQuitDialog();
+ if (!menuData.exit && quit()) {
+ if (displayQuitDialog())
+ quitGame();
}
}
}
@@ -556,6 +557,7 @@ int ToucheEngine::displayQuitDialog() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
switch (event.type) {
+ case Common::EVENT_RTL:
case Common::EVENT_QUIT:
quitLoop = true;
ret = 1;
diff --git a/engines/touche/opcodes.cpp b/engines/touche/opcodes.cpp
index 4405c614ac..b2b16eb29d 100644
--- a/engines/touche/opcodes.cpp
+++ b/engines/touche/opcodes.cpp
@@ -408,6 +408,10 @@ void ToucheEngine::op_setFlag() {
case 104:
_currentKeyCharNum = val;
break;
+ case 611:
+ if (val != 0)
+ quitGame();
+ break;
case 612:
_flagsTable[613] = getRandomNumber(val);
break;
diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp
index 4fcf6e114d..fedd40eb76 100644
--- a/engines/touche/saveload.cpp
+++ b/engines/touche/saveload.cpp
@@ -31,11 +31,6 @@
namespace Touche {
-enum {
- kCurrentGameStateVersion = 6,
- kGameStateDescriptionLen = 32
-};
-
static void saveOrLoad(Common::WriteStream &stream, uint16 &i) {
stream.writeUint16LE(i);
}
@@ -292,7 +287,7 @@ void ToucheEngine::loadGameStateData(Common::ReadStream *stream) {
if (stream->readUint32LE() != saveLoadEndMarker) {
warning("Corrupted gamestate data");
// if that ever happens, exit the game
- _flagsTable[611] = 1;
+ quitGame();
}
_flagsTable[614] = roomOffsX;
_flagsTable[615] = roomOffsY;
diff --git a/engines/touche/staticres.cpp b/engines/touche/staticres.cpp
index ec9a0ea903..a377a6e45f 100644
--- a/engines/touche/staticres.cpp
+++ b/engines/touche/staticres.cpp
@@ -889,6 +889,7 @@ const uint8 Graphics::_freGerFontData[] = {
0xC0, 0x00, 0x00,
};
+// spanish charset differs from original executable, see tracker item #2040311.
const uint16 Graphics::_spaFontOffs[] = {
0x0000, 0x0007, 0x0024, 0x0043, 0x0072, 0x00AD, 0x00E0, 0x0113, 0x0124, 0x0141,
0x015E, 0x0191, 0x01C4, 0x01E3, 0x01F8, 0x0215, 0x0232, 0x0269, 0x0286, 0x02BD,
@@ -904,11 +905,11 @@ const uint16 Graphics::_spaFontOffs[] = {
0x1462, 0x1499, 0x14A4, 0x14DB, 0x1512, 0x1549, 0x1580, 0x15B7, 0x15EE, 0x1625,
0x165C, 0x1667, 0x169E, 0x16D5, 0x16E0, 0x16EB, 0x1722, 0x172D, 0x1738, 0x176F,
0x178C, 0x17C3, 0x17FA, 0x1831, 0x1868, 0x1873, 0x187E, 0x18B5, 0x18C0, 0x18CB,
- 0x18D6, 0x18E1, 0x18FE, 0x1929, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x18D6, 0x18E1, 0x18FE, 0x1929, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x054B,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0703, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x1954
};
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index ac8e8a786a..e122187dcd 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -95,7 +95,7 @@ int ToucheEngine::init() {
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
return 0;
}
@@ -234,6 +234,13 @@ Common::Point ToucheEngine::getMousePos() const {
return _eventMan->getMousePos();
}
+void ToucheEngine::syncSoundSettings() {
+ readConfigurationSettings();
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+}
+
void ToucheEngine::mainLoop() {
restart();
@@ -245,10 +252,13 @@ void ToucheEngine::mainLoop() {
_inp_rightMouseButtonPressed = false;
if (ConfMan.hasKey("save_slot")) {
- loadGameState(ConfMan.getInt("save_slot"));
- _newEpisodeNum = 0;
- resetSortedKeyCharsTable();
- showCursor(true);
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0 && saveSlot <= 99) {
+ loadGameState(saveSlot);
+ _newEpisodeNum = 0;
+ resetSortedKeyCharsTable();
+ showCursor(true);
+ }
} else {
_newEpisodeNum = ConfMan.getInt("boot_param");
if (_newEpisodeNum == 0) {
@@ -258,7 +268,7 @@ void ToucheEngine::mainLoop() {
}
uint32 frameTimeStamp = _system->getMillis();
- for (uint32 cycleCounter = 0; _flagsTable[611] == 0; ++cycleCounter) {
+ for (uint32 cycleCounter = 0; !quit(); ++cycleCounter) {
if ((cycleCounter % 3) == 0) {
runCycle();
}
@@ -287,9 +297,6 @@ void ToucheEngine::processEvents(bool handleKeyEvents) {
Common::Event event;
while (_eventMan->pollEvent(event)) {
switch (event.type) {
- case Common::EVENT_QUIT:
- _flagsTable[611] = 1;
- break;
case Common::EVENT_KEYDOWN:
if (!handleKeyEvents) {
break;
@@ -297,7 +304,8 @@ void ToucheEngine::processEvents(bool handleKeyEvents) {
_flagsTable[600] = event.kbd.keycode;
if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
if (_displayQuitDialog) {
- _flagsTable[611] = displayQuitDialog();
+ if (displayQuitDialog())
+ quitGame();
}
} else if (event.kbd.keycode == Common::KEYCODE_F5) {
if (_flagsTable[618] == 0 && !_hideInventoryTexts) {
@@ -1248,10 +1256,11 @@ int ToucheEngine::getStringWidth(int num) const {
return Graphics::getStringWidth16(str);
}
-void ToucheEngine::drawString(uint16 color, int x, int y, int16 num) {
+void ToucheEngine::drawString(uint16 color, int x, int y, int16 num, StringType strType) {
+ const int xmax = (_language == Common::ES_ESP && strType == kStringTypeConversation) ? kScreenWidth - 20 : 0;
if (num) {
const char *str = getString(num);
- Graphics::drawString16(_offscreenBuffer, kScreenWidth, color, x, y, str);
+ Graphics::drawString16(_offscreenBuffer, kScreenWidth, color, x, y, str, xmax);
}
}
@@ -1828,7 +1837,7 @@ int ToucheEngine::handleActionMenuUnderCursor(const int16 *actions, int offs, in
_menuRedrawCounter = 2;
Common::Rect rect(0, y, kScreenWidth, y + h);
i = -1;
- while (_inp_rightMouseButtonPressed && _flagsTable[611] == 0) {
+ while (_inp_rightMouseButtonPressed && !quit()) {
Common::Point mousePos = getMousePos();
if (rect.contains(mousePos)) {
int c = (mousePos.y - y) / kTextHeight;
@@ -2414,7 +2423,7 @@ void ToucheEngine::drawCharacterConversation() {
}
drawConversationPanel();
for (int i = 0; i < 4; ++i) {
- drawString(214, 42, 328 + i * kTextHeight, _conversationChoicesTable[_scrollConversationChoiceOffset + i].msg);
+ drawString(214, 42, 328 + i * kTextHeight, _conversationChoicesTable[_scrollConversationChoiceOffset + i].msg, kStringTypeConversation);
}
updateScreenArea(0, 320, kScreenWidth, kScreenHeight - 320);
_conversationAreaCleared = false;
@@ -2422,7 +2431,7 @@ void ToucheEngine::drawCharacterConversation() {
void ToucheEngine::drawConversationString(int num, uint16 color) {
const int y = 328 + num * kTextHeight;
- drawString(color, 42, y, _conversationChoicesTable[num + _scrollConversationChoiceOffset].msg);
+ drawString(color, 42, y, _conversationChoicesTable[num + _scrollConversationChoiceOffset].msg, kStringTypeConversation);
updateScreenArea(0, y, kScreenWidth, kTextHeight);
}
@@ -2691,10 +2700,10 @@ bool ToucheEngine::sortPointsData(int num1, int num2) {
const int md2 = _programWalkTable[num1].point2;
_programPointsTable[md2].order = 0;
}
- bool quit = false;
+ bool quitLoop = false;
int order = 1;
- while (!quit) {
- quit = true;
+ while (!quitLoop) {
+ quitLoop = true;
for (uint i = 0; i < _programWalkTable.size(); ++i) {
const int md1 = _programWalkTable[i].point1;
const int md2 = _programWalkTable[i].point2;
@@ -2702,11 +2711,11 @@ bool ToucheEngine::sortPointsData(int num1, int num2) {
assert((md2 & 0x4000) == 0);
if (_programPointsTable[md1].order == order - 1 && _programPointsTable[md2].order > order) {
_programPointsTable[md2].order = order;
- quit = false;
+ quitLoop = false;
}
if (_programPointsTable[md2].order == order - 1 && _programPointsTable[md1].order > order) {
_programPointsTable[md1].order = order;
- quit = false;
+ quitLoop = false;
}
}
}
@@ -2938,9 +2947,9 @@ void ToucheEngine::markWalkPoints(int keyChar) {
resetPointsData(0);
if (pointsDataNum != -1) {
_programPointsTable[pointsDataNum].order = 1;
- bool quit = false;
- while (!quit) {
- quit = true;
+ bool quitLoop = false;
+ while (!quitLoop) {
+ quitLoop = true;
for (uint i = 0; i < _programWalkTable.size(); ++i) {
int16 md1 = _programWalkTable[i].point1;
int16 md2 = _programWalkTable[i].point2;
@@ -2948,11 +2957,11 @@ void ToucheEngine::markWalkPoints(int keyChar) {
assert((md2 & 0x4000) == 0);
if (_programPointsTable[md1].order != 0 && _programPointsTable[md2].order == 0) {
_programPointsTable[md2].order = 1;
- quit = false;
+ quitLoop = false;
}
if (_programPointsTable[md2].order != 0 && _programPointsTable[md1].order == 0) {
_programPointsTable[md1].order = 1;
- quit = false;
+ quitLoop = false;
}
}
}
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index c1bc12655f..f341769422 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -328,7 +328,14 @@ enum {
kCursorHeight = 42,
kTextHeight = 16,
kMaxProgramDataSize = 61440,
- kMaxSaveStates = 100
+ kMaxSaveStates = 100,
+ kGameStateDescriptionLen = 32, // Need these two values defined here
+ kCurrentGameStateVersion = 6 // for --list-saves support
+};
+
+enum StringType {
+ kStringTypeDefault,
+ kStringTypeConversation
};
class MidiPlayer;
@@ -356,6 +363,7 @@ public:
virtual int init();
virtual int go();
+ virtual void syncSoundSettings();
protected:
@@ -399,7 +407,7 @@ protected:
void setKeyCharMoney();
const char *getString(int num) const;
int getStringWidth(int num) const;
- void drawString(uint16 color, int x, int y, int16 num);
+ void drawString(uint16 color, int x, int y, int16 num, StringType strType = kStringTypeDefault);
void drawGameString(uint16 color, int x1, int y, const char *str);
int restartKeyCharScriptOnAction(int action, int obj1, int obj2);
void buildSpriteScalingTable(int z1, int z2);
diff --git a/graphics/dxa_player.cpp b/graphics/dxa_player.cpp
index 28a1bc4dbd..f4c93a51f1 100644
--- a/graphics/dxa_player.cpp
+++ b/graphics/dxa_player.cpp
@@ -24,6 +24,7 @@
*/
#include "common/endian.h"
+#include "common/file.h"
#include "graphics/dxa_player.h"
#include "common/util.h"
diff --git a/graphics/dxa_player.h b/graphics/dxa_player.h
index 5415e440d2..dbe39bbcee 100644
--- a/graphics/dxa_player.h
+++ b/graphics/dxa_player.h
@@ -27,11 +27,7 @@
#define GRAPHICS_DXA_PLAYER_H
#include "common/scummsys.h"
-#include "common/file.h"
-
-namespace Common {
- class File;
-}
+#include "common/stream.h"
namespace Graphics {
diff --git a/graphics/font.cpp b/graphics/font.cpp
index 0b0405b4b4..0f67899706 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -513,6 +513,7 @@ int bdf_read_bitmaps(Common::SeekableReadStream &fp, NewFontData* pf) {
}
/* read the next non-comment line, returns buf or NULL if EOF*/
+// TODO: Can we use SeekableReadStream::readLine resp. readLine_NEW instead?
char *bdf_getline(Common::SeekableReadStream &fp, char *buf, int len) {
int c;
char *b;
diff --git a/graphics/iff.cpp b/graphics/iff.cpp
index 514fba9cc0..b3846c5d26 100644
--- a/graphics/iff.cpp
+++ b/graphics/iff.cpp
@@ -219,7 +219,7 @@ void PBMDecoder::readBODY(Common::IFFChunk& chunk) {
switch (_bitmapHeader.pack) {
case 0:
- while (!chunk.eos()) {
+ while (!chunk.hasReadAll()) {
((byte*)_surface->pixels)[si++] = chunk.readByte();
}
break;
@@ -245,7 +245,9 @@ PackBitsReadStream::~PackBitsReadStream() {
}
bool PackBitsReadStream::eos() const {
- return _input->eos() & (_rStoragePos == _wStoragePos);
+ //FIXME: eos definition needs to be changed in parallaction engine
+ // which is the only place where this class is used
+ return _input->eos() && (_rStoragePos == _wStoragePos);
}
uint32 PackBitsReadStream::read(void *dataPtr, uint32 dataSize) {
@@ -291,6 +293,9 @@ void PackBitsReadStream::unpack() {
while (_out < _outEnd && !_input->eos()) {
byteRun = _input->readByte();
+ //FIXME: eos definition needs to be changed in parallaction engine
+ // which is the only place where this class is used
+ //if (_input->eos()) break;
if (byteRun <= 127) {
i = byteRun + 1;
for (j = 0; j < i; j++) {
diff --git a/graphics/imageman.cpp b/graphics/imageman.cpp
index 83ffc40c99..44ac7c9e75 100644
--- a/graphics/imageman.cpp
+++ b/graphics/imageman.cpp
@@ -26,14 +26,13 @@
#include "graphics/imageman.h"
#include "graphics/surface.h"
+#include "common/unzip.h"
+
DECLARE_SINGLETON(Graphics::ImageManager);
namespace Graphics {
-ImageManager::ImageManager() : _surfaces()
-#ifdef USE_ZLIB
-, _archives()
-#endif
-{
+
+ImageManager::ImageManager() {
}
ImageManager::~ImageManager() {
@@ -44,36 +43,21 @@ ImageManager::~ImageManager() {
*pos = 0;
}
_surfaces.clear();
-#ifdef USE_ZLIB
- for (ZipIterator pos2 = _archives.begin(); pos2 != _archives.end(); ++pos2) {
- unzClose(pos2->file);
- }
- _archives.clear();
-#endif
}
bool ImageManager::addArchive(const Common::String &name) {
#ifdef USE_ZLIB
- unzFile newFile = unzOpen(name.c_str());
- if (!newFile)
+ Common::ZipArchive *arch = new Common::ZipArchive(name);
+ if (!arch || !arch->isOpen())
return false;
- Archive arch;
- arch.file = newFile;
- arch.filename = name;
- _archives.push_back(arch);
+ _archives.add(name, Common::ArchivePtr(arch));
#endif
return true;
}
-void ImageManager::remArchive(const Common::String &name) {
+void ImageManager::removeArchive(const Common::String &name) {
#ifdef USE_ZLIB
- for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) {
- if (pos->filename.compareToIgnoreCase(name) == 0) {
- unzClose(pos->file);
- _archives.erase(pos);
- break;
- }
- }
+ _archives.remove(name);
#endif
}
@@ -86,39 +70,21 @@ bool ImageManager::registerSurface(const Common::String &name, Surface *surf) {
if (!newHandle)
return false;
- if (!surf) {
+ if (!surf)
surf = ImageDecoder::loadFile(name);
- if (!surf) {
+
#ifdef USE_ZLIB
- ZipIterator file = _archives.end();
- for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) {
- if (unzLocateFile(pos->file, name.c_str(), 2) == UNZ_OK) {
- file = pos;
- break;
- }
- }
-
- if (file == _archives.end())
- return false;
-
- unz_file_info fileInfo;
- unzOpenCurrentFile(file->file);
- unzGetCurrentFileInfo(file->file, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- uint8 *buffer = new uint8[fileInfo.uncompressed_size];
- assert(buffer);
- unzReadCurrentFile(file->file, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(file->file);
- Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size);
- surf = ImageDecoder::loadFile(stream);
- delete[] buffer;
-
- if (!surf)
- return false;
-#else
- return false;
-#endif
+ if (!surf) {
+ Common::SeekableReadStream *stream = _archives.openFile(name);
+ if (stream) {
+ surf = ImageDecoder::loadFile(*stream);
+ delete stream;
}
}
+#endif
+
+ if (!surf)
+ return false;
newHandle->surface = surf;
newHandle->name = name;
diff --git a/graphics/imageman.h b/graphics/imageman.h
index c3b56c311f..f555b4c844 100644
--- a/graphics/imageman.h
+++ b/graphics/imageman.h
@@ -26,12 +26,14 @@
#define GRAPHICS_IMAGEMAN_H
#include "common/scummsys.h"
+
+#include "common/archive.h"
#include "common/singleton.h"
#include "common/str.h"
#include "common/list.h"
-#include "common/unzip.h"
namespace Graphics {
+
struct Surface;
class ImageManager : public Common::Singleton<ImageManager> {
@@ -53,7 +55,7 @@ public:
*
* @param name the name of the archive
*/
- void remArchive(const Common::String &name);
+ void removeArchive(const Common::String &name);
/**
* registers a surface to the ImageManager.
@@ -93,20 +95,11 @@ private:
Surface *surface;
};
typedef Common::List<Entry*>::iterator Iterator;
-#ifdef USE_ZLIB
- struct Archive {
- unzFile file;
- Common::String filename;
- };
- typedef Common::List<Archive>::iterator ZipIterator;
-#endif
Iterator searchHandle(const Common::String &name);
Common::List<Entry*> _surfaces;
-#ifdef USE_ZLIB
- Common::List<Archive> _archives;
-#endif
+ Common::SearchSet _archives;
};
} // end of namespace Graphics
diff --git a/graphics/module.mk b/graphics/module.mk
index a44042a044..6a5f7f9e22 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -15,8 +15,9 @@ MODULE_OBJS := \
mpeg_player.o \
primitives.o \
scaler.o \
- scaler/thumbnail.o \
+ scaler/thumbnail_intern.o \
surface.o \
+ thumbnail.o \
surface-keycolored.o
ifndef DISABLE_SCALERS
diff --git a/graphics/scaler.h b/graphics/scaler.h
index 2cf3f66239..95900de412 100644
--- a/graphics/scaler.h
+++ b/graphics/scaler.h
@@ -78,10 +78,22 @@ enum {
extern void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height);
/**
- * creates a thumbnail from the current screen (without overlay)
+ * Creates a thumbnail from the current screen (without overlay).
+ *
* @param surf a surface (will always have 16 bpp after this for now)
* @return false if a error occured
*/
-extern bool createThumbnailFromScreen(Graphics::Surface* surf);
+extern bool createThumbnailFromScreen(Graphics::Surface *surf);
+
+/**
+ * Creates a thumbnail from a buffer.
+ *
+ * @param surf destination surface (will always have 16 bpp after this for now)
+ * @param pixels raw pixel data
+ * @param w width
+ * @param h height
+ * @param palette palette in RGB format
+ */
+extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette);
#endif
diff --git a/graphics/scaler/hq2x_i386.asm b/graphics/scaler/hq2x_i386.asm
index ed194441ed..f176c340c1 100644
--- a/graphics/scaler/hq2x_i386.asm
+++ b/graphics/scaler/hq2x_i386.asm
@@ -1840,3 +1840,8 @@ FuncTable2:
dd ..@cross8, ..@flag0, ..@flag0, ..@flag0,
dd ..@flag0, ..@flag0, ..@flag0, ..@flag0
+
+%ifidn __OUTPUT_FORMAT__,elf
+section .note.GNU-stack noalloc noexec nowrite progbits
+%endif
+
diff --git a/graphics/scaler/hq3x_i386.asm b/graphics/scaler/hq3x_i386.asm
index e713fdd51a..8ffb2d5aba 100644
--- a/graphics/scaler/hq3x_i386.asm
+++ b/graphics/scaler/hq3x_i386.asm
@@ -2432,3 +2432,8 @@ FuncTable2:
dd ..@cross8, ..@flag0, ..@flag0, ..@flag0,
dd ..@flag0, ..@flag0, ..@flag0, ..@flag0
+
+%ifidn __OUTPUT_FORMAT__,elf
+section .note.GNU-stack noalloc noexec nowrite progbits
+%endif
+
diff --git a/graphics/scaler/thumbnail.cpp b/graphics/scaler/thumbnail_intern.cpp
index f1caa5d2e5..bdfa0ff5f6 100644
--- a/graphics/scaler/thumbnail.cpp
+++ b/graphics/scaler/thumbnail_intern.cpp
@@ -126,70 +126,93 @@ static bool grabScreen565(Graphics::Surface *surf) {
return true;
}
-bool createThumbnailFromScreen(Graphics::Surface* surf) {
- assert(surf);
-
- int screenWidth = g_system->getWidth();
- int screenHeight = g_system->getHeight();
-
- Graphics::Surface screen;
-
- if (!grabScreen565(&screen))
- return false;
+static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
+ uint16 width = in.w;
+ uint16 inHeight = in.h;
- uint16 width = screenWidth;
-
- if (screenWidth < 320) {
+ if (width < 320) {
// Special case to handle MM NES (uses a screen width of 256)
width = 320;
// center MM NES screen
Graphics::Surface newscreen;
- newscreen.create(width, screen.h, screen.bytesPerPixel);
+ newscreen.create(width, in.h, in.bytesPerPixel);
- uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0);
- uint8 *src = (uint8*)screen.getBasePtr(0, 0);
- uint16 height = screen.h;
+ uint8 *dst = (uint8*)newscreen.getBasePtr((320 - in.w) / 2, 0);
+ const uint8 *src = (uint8*)in.getBasePtr(0, 0);
+ uint16 height = in.h;
while (height--) {
- memcpy(dst, src, screen.pitch);
+ memcpy(dst, src, in.pitch);
dst += newscreen.pitch;
- src += screen.pitch;
+ src += in.pitch;
}
- screen.free();
- screen = newscreen;
- } else if (screenWidth == 720) {
+ in.free();
+ in = newscreen;
+ } else if (width == 720) {
// Special case to handle Hercules mode
width = 640;
- screenHeight = 400;
+ inHeight = 400;
// cut off menu and so on..
Graphics::Surface newscreen;
- newscreen.create(width, 400, screen.bytesPerPixel);
+ newscreen.create(width, 400, in.bytesPerPixel);
- uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2);
- uint8 *src = (uint8*)screen.getBasePtr(41, 28);
+ uint8 *dst = (uint8*)in.getBasePtr(0, (400 - 240) / 2);
+ const uint8 *src = (uint8*)in.getBasePtr(41, 28);
for (int y = 0; y < 240; ++y) {
- memcpy(dst, src, 640 * screen.bytesPerPixel);
+ memcpy(dst, src, 640 * in.bytesPerPixel);
dst += newscreen.pitch;
- src += screen.pitch;
+ src += in.pitch;
}
- screen.free();
- screen = newscreen;
+ in.free();
+ in = newscreen;
}
- uint16 newHeight = !(screenHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
+ uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
int gBitFormatBackUp = gBitFormat;
gBitFormat = 565;
- surf->create(kThumbnailWidth, newHeight, sizeof(uint16));
- createThumbnail((const uint8*)screen.pixels, width * sizeof(uint16), (uint8*)surf->pixels, surf->pitch, width, screenHeight);
+ out.create(kThumbnailWidth, newHeight, sizeof(uint16));
+ createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight);
gBitFormat = gBitFormatBackUp;
- screen.free();
+ in.free();
return true;
}
+
+bool createThumbnailFromScreen(Graphics::Surface* surf) {
+ assert(surf);
+
+ Graphics::Surface screen;
+
+ if (!grabScreen565(&screen))
+ return false;
+
+ return createThumbnail(*surf, screen);
+}
+
+bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) {
+ assert(surf);
+
+ Graphics::Surface screen;
+ screen.create(w, h, 2);
+
+ for (uint y = 0; y < screen.h; ++y) {
+ for (uint x = 0; x < screen.w; ++x) {
+ byte r, g, b;
+ r = palette[pixels[y * w + x] * 3];
+ g = palette[pixels[y * w + x] * 3 + 1];
+ b = palette[pixels[y * w + x] * 3 + 2];
+
+ ((uint16 *)screen.pixels)[y * screen.w + x] = RGBToColor<ColorMasks<565> >(r, g, b);
+ }
+ }
+
+ return createThumbnail(*surf, screen);
+}
+
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index a9f3e75886..263a4fd23b 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -66,6 +66,11 @@ void Surface::free() {
bytesPerPixel = 0;
}
+void Surface::copyFrom(const Surface &surf) {
+ create(surf.w, surf.h, surf.bytesPerPixel);
+ memcpy(pixels, surf.pixels, h * pitch);
+}
+
void Surface::hLine(int x, int y, int x2, uint32 color) {
// Clipping
if (y < 0 || y >= h)
diff --git a/graphics/surface.h b/graphics/surface.h
index ff1ddda695..747bda9a26 100644
--- a/graphics/surface.h
+++ b/graphics/surface.h
@@ -30,7 +30,6 @@
namespace Graphics {
-
/**
* An arbitrary graphics surface, which can be the target (or source) of blit
* operations, font rendering, etc.
@@ -67,6 +66,12 @@ struct Surface {
*/
void free();
+ /**
+ * Copies data from another Surface, this calls *free* on the current surface, to assure
+ * it being clean.
+ */
+ void copyFrom(const Surface &surf);
+
void drawLine(int x0, int y0, int x1, int y1, uint32 color);
void hLine(int x, int y, int x2, uint32 color);
void vLine(int x, int y, int y2, uint32 color);
@@ -76,6 +81,18 @@ struct Surface {
void move(int dx, int dy, int height);
};
+/**
+ * For safe deletion of surface with SharedPtr.
+ * The deleter assures Surface::free is called on
+ * deletion.
+ */
+struct SharedPtrSurfaceDeleter {
+ void operator()(Surface *ptr) {
+ ptr->free();
+ delete ptr;
+ }
+};
+
} // End of namespace Graphics
diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp
new file mode 100644
index 0000000000..905fea3d93
--- /dev/null
+++ b/graphics/thumbnail.cpp
@@ -0,0 +1,174 @@
+/* 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 "graphics/thumbnail.h"
+#include "graphics/scaler.h"
+#include "common/endian.h"
+#include "common/system.h"
+
+namespace Graphics {
+
+namespace {
+#define THMB_VERSION 1
+
+struct ThumbnailHeader {
+ uint32 type;
+ uint32 size;
+ byte version;
+ uint16 width, height;
+ byte bpp;
+};
+
+#define ThumbnailHeaderSize (4+4+1+2+2+1)
+
+inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
+ r = (((color >> 11) & 0x1F) << 3);
+ g = (((color >> 5) & 0x3F) << 2);
+ b = ((color&0x1F) << 3);
+}
+
+bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) {
+ header.type = in.readUint32BE();
+ // We also accept the bad 'BMHT' header here, for the sake of compatibility
+ // with some older savegames which were written incorrectly due to a bug in
+ // ScummVM which wrote the thumb header type incorrectly on LE systems.
+ if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) {
+ if (outputWarnings)
+ warning("couldn't find thumbnail header type");
+ return false;
+ }
+
+ header.size = in.readUint32BE();
+ header.version = in.readByte();
+
+ if (header.version > THMB_VERSION) {
+ if (outputWarnings)
+ warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION);
+ return false;
+ }
+
+ header.width = in.readUint16BE();
+ header.height = in.readUint16BE();
+ header.bpp = in.readByte();
+
+ return true;
+}
+} // end of anonymous namespace
+
+bool checkThumbnailHeader(Common::SeekableReadStream &in) {
+ uint32 position = in.pos();
+ ThumbnailHeader header;
+
+ bool hasHeader = loadHeader(in, header, false);
+
+ in.seek(position, SEEK_SET);
+
+ return hasHeader;
+}
+
+bool skipThumbnailHeader(Common::SeekableReadStream &in) {
+ uint32 position = in.pos();
+ ThumbnailHeader header;
+
+ if (!loadHeader(in, header, false)) {
+ in.seek(position, SEEK_SET);
+ return false;
+ }
+
+ in.seek(header.size - (in.pos() - position), SEEK_CUR);
+ return true;
+}
+
+bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to) {
+ ThumbnailHeader header;
+
+ if (!loadHeader(in, header, true))
+ return false;
+
+ if (header.bpp != 2) {
+ warning("trying to load thumbnail with unsupported bit depth %d", header.bpp);
+ return false;
+ }
+
+ to.create(header.width, header.height, sizeof(OverlayColor));
+
+ OverlayColor *pixels = (OverlayColor *)to.pixels;
+ for (int y = 0; y < to.h; ++y) {
+ for (int x = 0; x < to.w; ++x) {
+ uint8 r, g, b;
+ colorToRGB(in.readUint16BE(), r, g, b);
+
+ // converting to current OSystem Color
+ *pixels++ = g_system->RGBToColor(r, g, b);
+ }
+ }
+
+ return true;
+}
+
+bool saveThumbnail(Common::WriteStream &out) {
+ Graphics::Surface thumb;
+
+ if (!createThumbnailFromScreen(&thumb)) {
+ warning("Couldn't create thumbnail from screen, aborting thumbnail save");
+ return false;
+ }
+
+ bool success = saveThumbnail(out, thumb);
+ thumb.free();
+
+ return success;
+}
+
+bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) {
+ if (thumb.bytesPerPixel != 2) {
+ warning("trying to save thumbnail with bpp different than 2");
+ return false;
+ }
+
+ ThumbnailHeader header;
+ header.type = MKID_BE('THMB');
+ header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
+ header.version = THMB_VERSION;
+ header.width = thumb.w;
+ header.height = thumb.h;
+ header.bpp = thumb.bytesPerPixel;
+
+ out.writeUint32BE(header.type);
+ out.writeUint32BE(header.size);
+ out.writeByte(header.version);
+ out.writeUint16BE(header.width);
+ out.writeUint16BE(header.height);
+ out.writeByte(header.bpp);
+
+ // TODO: for later this shouldn't be casted to uint16...
+ uint16 *pixels = (uint16 *)thumb.pixels;
+ for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
+ out.writeUint16BE(*pixels);
+
+ return true;
+}
+
+} // end of namespace Graphics
+
diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h
new file mode 100644
index 0000000000..0553306519
--- /dev/null
+++ b/graphics/thumbnail.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef GRAPHICS_THUMBNAIL_H
+#define GRAPHICS_THUMBNAIL_H
+
+#include "common/stream.h"
+#include "graphics/surface.h"
+
+namespace Graphics {
+
+/**
+ * Checks for presence of the thumbnail save header.
+ * Seeks automatically back to start position after check.
+ *
+ * @param in stream to check for header
+ */
+bool checkThumbnailHeader(Common::SeekableReadStream &in);
+
+/**
+ * Skips a thumbnail header, if present.
+ *
+ * @param in stream to process
+ */
+bool skipThumbnailHeader(Common::SeekableReadStream &in);
+
+/**
+ * Lodas a thumbnail from the given input stream.
+ * The loaded thumbnail will be automatically converted to the
+ * current overlay pixelformat.
+ */
+bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to);
+
+/**
+ * Saves a thumbnail to the given write stream.
+ * Automatically creates a thumbnail from screen contents.
+ */
+bool saveThumbnail(Common::WriteStream &out);
+
+/**
+ * Saves a (given) thumbnail to the given write stream.
+ */
+bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb);
+
+} // end of namespace Graphics
+
+#endif
+
diff --git a/gui/ThemeModern.cpp b/gui/ThemeModern.cpp
index 177171b40c..fa8c29e616 100644
--- a/gui/ThemeModern.cpp
+++ b/gui/ThemeModern.cpp
@@ -120,7 +120,7 @@ ThemeModern::~ThemeModern() {
for (int i = 0; i < kImageHandlesMax; ++i) {
ImageMan.unregisterSurface(_imageHandles[i]);
}
- ImageMan.remArchive(_stylefile + ".zip");
+ ImageMan.removeArchive(_stylefile + ".zip");
}
bool ThemeModern::init() {
@@ -1159,6 +1159,15 @@ OverlayColor ThemeModern::getColor(State state) {
return _colors[kColorStateEnabled];
}
+const Graphics::Surface *ThemeModern::getImageSurface(const kThemeImages n) const {
+ if (n == kImageLogo)
+ return _images[kThemeLogo];
+ else if (n == kImageLogoSmall)
+ return _images[kThemeLogoSmall];
+ else
+ return 0;
+}
+
void ThemeModern::resetupGuiRenderer() {
if (_lastUsedBitMask == gBitFormat || !_initOk) {
// ok same format no need to reload
@@ -1334,6 +1343,7 @@ void ThemeModern::processExtraValues() {
_imageHandles[kWidgetArrow] = _evaluator->getStringVar("pix_widget_arrow");
_imageHandles[kThemeLogo] = _evaluator->getStringVar("pix_theme_logo");
+ _imageHandles[kThemeLogoSmall] = _evaluator->getStringVar("pix_theme_logo_small");
_imageHandles[kGUICursor] = _evaluator->getStringVar("pix_cursor_image");
diff --git a/gui/ThemeModern.h b/gui/ThemeModern.h
index a3cb71510c..d64d18242e 100644
--- a/gui/ThemeModern.h
+++ b/gui/ThemeModern.h
@@ -82,7 +82,7 @@ public:
int getTabPadding() const;
bool supportsImages() const { return true; }
- const Graphics::Surface *getImageSurface(const kThemeImages n) const { return n == kImageLogo ? _images[kThemeLogo] : 0; }
+ const Graphics::Surface *getImageSurface(const kThemeImages n) const;
private:
void colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end, uint factor = 1);
void drawRect(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
@@ -193,18 +193,19 @@ private:
kWidgetSmallBkgd = 38,
kThemeLogo = 39,
+ kThemeLogoSmall = 40,
- kPopUpWidgetBkgdCorner = 40,
- kPopUpWidgetBkgdTop = 41,
- kPopUpWidgetBkgdLeft = 42,
- kPopUpWidgetBkgd = 43,
+ kPopUpWidgetBkgdCorner = 41,
+ kPopUpWidgetBkgdTop = 42,
+ kPopUpWidgetBkgdLeft = 43,
+ kPopUpWidgetBkgd = 44,
- kEditTextBkgdCorner = 44,
- kEditTextBkgdTop = 45,
- kEditTextBkgdLeft = 46,
- kEditTextBkgd = 47,
+ kEditTextBkgdCorner = 45,
+ kEditTextBkgdTop = 46,
+ kEditTextBkgdLeft = 47,
+ kEditTextBkgd = 48,
- kGUICursor = 48,
+ kGUICursor = 49,
kImageHandlesMax
};
diff --git a/gui/about.cpp b/gui/about.cpp
index 758f3ee6a7..99469b9ae4 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -57,7 +57,7 @@ enum {
static const char *copyright_text[] = {
"\\C""",
-"\\C""Copyright (C) 2002-2007 The ScummVM project",
+"\\C""Copyright (C) 2001-2008 The ScummVM project",
"\\C""http://www.scummvm.org",
"\\C""",
"\\C""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 binary.",
diff --git a/gui/browser.cpp b/gui/browser.cpp
index 41d3d15bb6..978187c17e 100644
--- a/gui/browser.cpp
+++ b/gui/browser.cpp
@@ -107,7 +107,7 @@ int BrowserDialog::runModal() {
err = FSRefMakePath(&ref, (UInt8*)buf, sizeof(buf)-1);
assert(err == noErr);
- _choice = FilesystemNode(buf);
+ _choice = Common::FilesystemNode(buf);
choiceMade = true;
}
@@ -160,9 +160,9 @@ BrowserDialog::BrowserDialog(const char *title, bool dirBrowser)
void BrowserDialog::open() {
if (ConfMan.hasKey("browser_lastpath"))
- _node = FilesystemNode(ConfMan.get("browser_lastpath"));
+ _node = Common::FilesystemNode(ConfMan.get("browser_lastpath"));
if (!_node.isDirectory())
- _node = FilesystemNode(".");
+ _node = Common::FilesystemNode(".");
// Alway refresh file list
updateListing();
@@ -227,8 +227,9 @@ void BrowserDialog::updateListing() {
ConfMan.set("browser_lastpath", _node.getPath());
// Read in the data from the file system
- FilesystemNode::ListMode listMode = _isDirBrowser ? FilesystemNode::kListDirectoriesOnly
- : FilesystemNode::kListAll;
+ Common::FilesystemNode::ListMode listMode =
+ _isDirBrowser ? Common::FilesystemNode::kListDirectoriesOnly
+ : Common::FilesystemNode::kListAll;
if (!_node.getChildren(_nodeContent, listMode)) {
_nodeContent.clear();
} else {
@@ -237,7 +238,7 @@ void BrowserDialog::updateListing() {
// Populate the ListWidget
Common::StringList list;
- for (FSList::iterator i = _nodeContent.begin(); i != _nodeContent.end(); ++i) {
+ for (Common::FSList::iterator i = _nodeContent.begin(); i != _nodeContent.end(); ++i) {
if (!_isDirBrowser && i->isDirectory())
list.push_back(i->getDisplayName() + "/");
else
diff --git a/gui/browser.h b/gui/browser.h
index d330e32269..c8bdec26a2 100644
--- a/gui/browser.h
+++ b/gui/browser.h
@@ -39,8 +39,6 @@ class ListWidget;
class StaticTextWidget;
class BrowserDialog : public Dialog {
- typedef Common::String String;
- typedef Common::StringList StringList;
public:
BrowserDialog(const char *title, bool dirBrowser);
@@ -52,7 +50,7 @@ public:
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
#endif
- const FilesystemNode &getResult() { return _choice; }
+ const Common::FilesystemNode &getResult() { return _choice; }
protected:
#ifdef MACOSX
@@ -60,10 +58,10 @@ protected:
#else
ListWidget *_fileList;
StaticTextWidget *_currentPath;
- FilesystemNode _node;
- FSList _nodeContent;
+ Common::FilesystemNode _node;
+ Common::FSList _nodeContent;
#endif
- FilesystemNode _choice;
+ Common::FilesystemNode _choice;
bool _isDirBrowser;
#ifndef MACOSX
diff --git a/gui/credits.h b/gui/credits.h
index 1afec250a6..c04a99ddbd 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -7,6 +7,12 @@ static const char *credits[] = {
"\\C\\c0""Max Horn",
"\\C\\c0""Eugene Sandulenko",
"\\C\\c0""",
+"\\C\\c1""Retired Project Leaders",
+"\\C\\c0""Vincent Hamm",
+"\\C\\c2""ScummVM co-founder, Original Cruise/CinE author",
+"\\C\\c0""Ludvig Strigeus",
+"\\C\\c2""Original ScummVM and SimonVM author",
+"\\C\\c0""",
"\\C\\c1""Engine Teams",
"\\C\\c1""SCUMM",
"\\C\\c0""Torbj\366rn Andersson",
@@ -138,7 +144,6 @@ static const char *credits[] = {
"\\C\\c0""Kostas Nakos",
"\\C\\c0""",
"\\C\\c1""PlayStation 2",
-"\\C\\c0""Robert G\366ffringmann",
"\\C\\c0""Max Lingua",
"\\C\\c0""",
"\\C\\c1""PSP (PlayStation Portable)",
@@ -169,11 +174,13 @@ static const char *credits[] = {
"\\C\\c0""",
"\\C\\c1""Miscellaneous",
"\\C\\c0""David Corrales-Lopez",
-"\\C\\c2""Filesystem access improvements",
+"\\C\\c2""Filesystem access improvements (GSoC 2007 task)",
"\\C\\c0""Jerome Fisher",
"\\C\\c2""MT-32 emulator",
"\\C\\c0""Jochen Hoenicke",
"\\C\\c2""Speaker & PCjr sound support, Adlib work",
+"\\C\\c0""Chris Page",
+"\\C\\c2""Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task)",
"\\C\\c0""Robin Watts",
"\\C\\c2""ARM assembly routines for nice speedups on several ports; improvements to the sound mixer",
"\\C\\c0""",
@@ -197,20 +204,22 @@ static const char *credits[] = {
"\\C\\c2""Help with GUI implementation",
"\\C\\c0""Jamieson Christian",
"\\C\\c2""iMUSE, MIDI, all things musical",
+"\\C\\c0""Hans-J\366rg Frieden",
+"\\C\\c2""Former AmigaOS 4 packager",
+"\\C\\c0""Robert G\366ffringmann",
+"\\C\\c2""Original PS2 porter",
"\\C\\c0""R\374diger Hanke",
"\\C\\c2""Port: MorphOS",
-"\\C\\c0""Vincent Hamm",
-"\\C\\c2""ScummVM co-founder, Original Cruise/CinE author",
"\\C\\c0""Felix Jakschitsch",
"\\C\\c2""Zak256 reverse engineering",
"\\C\\c0""Mutwin Kraus",
"\\C\\c2""Original MacOS porter",
"\\C\\c0""Peter Moraliyski",
"\\C\\c2""Port: GP32",
+"\\C\\c0""Juha Niemim\344ki",
+"\\C\\c2""Formaer AmigaOS 4 packager",
"\\C\\c0""Jeremy Newman",
"\\C\\c2""Former webmaster",
-"\\C\\c0""Ludvig Strigeus",
-"\\C\\c2""Original ScummVM and SimonVM author",
"\\C\\c0""Lionel Ulmer",
"\\C\\c2""Port: X11",
"\\C\\c0""Won Star",
@@ -221,9 +230,7 @@ static const char *credits[] = {
"\\C\\c0""",
"\\C\\c1""Packages",
"\\C\\c1""AmigaOS 4",
-"\\C\\c0""Hans-J\366rg Frieden",
"\\C\\c0""Hubert Maier",
-"\\C\\c0""Juha Niemim\344ki",
"\\C\\c0""",
"\\C\\c1""Atari/FreeMiNT",
"\\C\\c0""Keith Scroggins",
@@ -290,6 +297,8 @@ static const char *credits[] = {
"\\C\\c2""PSP port contributions",
"\\C\\c0""Thierry Crozat",
"\\C\\c2""Support for Broken Sword 1 Macintosh version",
+"\\C\\c0""Martin Doucha",
+"\\C\\c2""CinE engine objectification",
"\\C\\c0""Thomas Fach-Pedersen",
"\\C\\c2""ProTracker module player",
"\\C\\c0""Benjamin Haisch",
@@ -338,10 +347,14 @@ static const char *credits[] = {
"\\C\\c2""For the original MT-32 emulator",
"\\C\\c0""Kevin Carnes",
"\\C\\c2""For Scumm16, the basis of ScummVM's older gfx codecs",
+"\\C\\c0""Curt Coder",
+"\\C\\c2""For the original TrollVM (preAGI) code",
"\\C\\c0""Patrick Combet",
"\\C\\c2""For the original Gobliiins ADL player",
"\\C\\c0""Ivan Dubrov",
"\\C\\c2""For contributing the initial version of the Gobliiins engine",
+"\\C\\c0""Till Kresslein",
+"\\C\\c2""For design of modern ScummVM GUI",
"\\C\\c0""Jezar",
"\\C\\c2""For his freeverb filter implementation",
"\\C\\c0""Jim Leiterman",
@@ -354,6 +367,8 @@ static const char *credits[] = {
"\\C\\c2""For ScummRev, and much obscure code/documentation",
"\\C\\c0""Tristan",
"\\C\\c2""For additional work on the original MT-32 emulator",
+"\\C\\c0""James Woodcock",
+"\\C\\c2""Soundtrack enhancements",
"\\C\\c0""Tony Warriner and everyone at Revolution Software Ltd. for sharing with us the source of some of their brilliant games, allowing us to release Beneath a Steel Sky as freeware... and generally being supportive above and beyond the call of duty.",
"\\C\\c0""",
"\\C\\c0""John Passfield and Steve Stamatiadis for sharing the source of their classic title, Flight of the Amazon Queen and also being incredibly supportive.",
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 34c4ebf474..e9f718f4f0 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -29,6 +29,7 @@
#include "common/events.h"
#include "common/fs.h"
#include "common/util.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "gui/about.h"
@@ -45,6 +46,7 @@
#include "gui/TabWidget.h"
#include "gui/PopUpWidget.h"
#include "graphics/cursorman.h"
+#include "graphics/scaler.h"
#include "sound/mididrv.h"
@@ -61,7 +63,10 @@ enum {
kAddGameCmd = 'ADDG',
kEditGameCmd = 'EDTG',
kRemoveGameCmd = 'REMG',
+ kLoadGameCmd = 'LOAD',
kQuitCmd = 'QUIT',
+ kChooseCmd = 'CHOS',
+ kDelCmd = 'DEL ',
kCmdGlobalGraphicsOverride = 'OGFX',
@@ -390,7 +395,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
if (browser.runModal() > 0) {
// User made this choice...
- FilesystemNode file(browser.getResult());
+ Common::FilesystemNode file(browser.getResult());
_soundFont->setLabel(file.getPath());
if (!file.getPath().empty() && (file.getPath() != "None"))
@@ -408,7 +413,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
BrowserDialog browser("Select directory with game data", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
// TODO: Verify the game can be found in the new directory... Best
// done with optional specific gameid to pluginmgr detectgames?
@@ -426,7 +431,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
BrowserDialog browser("Select additional game directory", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
_extraPathWidget->setLabel(dir.getPath());
draw();
}
@@ -438,7 +443,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
BrowserDialog browser("Select directory for saved games", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
_savePathWidget->setLabel(dir.getPath());
draw();
}
@@ -450,7 +455,10 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
// Write back changes made to config object
String newDomain(_domainWidget->getEditString());
if (newDomain != _domain) {
- if (newDomain.empty() || ConfMan.hasGameDomain(newDomain)) {
+ if (newDomain.empty()
+ || newDomain.hasPrefix("_")
+ || newDomain == ConfigManager::kApplicationDomain
+ || ConfMan.hasGameDomain(newDomain)) {
MessageDialog alert("This game ID is already taken. Please choose another one.");
alert.runModal();
return;
@@ -465,6 +473,293 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
}
}
+class SaveLoadChooser : public GUI::Dialog {
+ typedef Common::String String;
+ typedef Common::StringList StringList;
+protected:
+ GUI::ListWidget *_list;
+ GUI::ButtonWidget *_chooseButton;
+ GUI::ButtonWidget *_deleteButton;
+ GUI::GraphicsWidget *_gfxWidget;
+ GUI::ContainerWidget *_container;
+ GUI::StaticTextWidget *_date;
+ GUI::StaticTextWidget *_time;
+ GUI::StaticTextWidget *_playtime;
+
+ const EnginePlugin *_plugin;
+ bool _delSupport;
+ bool _metaInfoSupport;
+ bool _thumbnailSupport;
+ bool _saveDateSupport;
+ bool _playTimeSupport;
+ String _target;
+ SaveStateList _saveList;
+
+ uint8 _fillR, _fillG, _fillB;
+
+ void updateSaveList();
+ void updateSelection(bool redraw);
+public:
+ SaveLoadChooser(const String &title, const String &buttonLabel);
+ ~SaveLoadChooser();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ void setList(const StringList& list);
+ int runModal(const EnginePlugin *plugin, const String &target);
+
+ virtual void reflowLayout();
+
+ virtual void close();
+};
+
+SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
+ : Dialog("scummsaveload"), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
+ _delSupport = _metaInfoSupport = _thumbnailSupport = _saveDateSupport = _playTimeSupport = false;
+
+ _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+
+ new StaticTextWidget(this, "scummsaveload_title", title);
+
+ // Add choice list
+ _list = new GUI::ListWidget(this, "scummsaveload_list");
+ _list->setNumberingMode(GUI::kListNumberingOff);
+
+ _gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
+
+ _date = new StaticTextWidget(this, 0, 0, 10, 10, "No date saved", kTextAlignCenter);
+ _time = new StaticTextWidget(this, 0, 0, 10, 10, "No time saved", kTextAlignCenter);
+ _playtime = new StaticTextWidget(this, 0, 0, 10, 10, "No playtime saved", kTextAlignCenter);
+
+ // Buttons
+ new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
+ _chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
+ _chooseButton->setEnabled(false);
+
+ _deleteButton = new GUI::ButtonWidget(this, "scummsaveload_delete", "Delete", kDelCmd, 0);
+ _deleteButton->setEnabled(false);
+
+ _delSupport = _metaInfoSupport = _thumbnailSupport = false;
+
+ _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
+ _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+}
+
+SaveLoadChooser::~SaveLoadChooser() {
+}
+
+int SaveLoadChooser::runModal(const EnginePlugin *plugin, const String &target) {
+ if (_gfxWidget)
+ _gfxWidget->setGfx(0);
+
+ _plugin = plugin;
+ _target = target;
+ _delSupport = (*_plugin)->hasFeature(MetaEngine::kSupportsDeleteSave);
+ _metaInfoSupport = (*_plugin)->hasFeature(MetaEngine::kSupportsMetaInfos);
+ _thumbnailSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSupportsThumbnails);
+ _saveDateSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSupportsSaveDate);
+ _playTimeSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSupportsSavePlayTime);
+ reflowLayout();
+ updateSaveList();
+
+ int ret = Dialog::runModal();
+ return ret;
+}
+
+void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ int selItem = _list->getSelected();
+
+ switch (cmd) {
+ case GUI::kListItemActivatedCmd:
+ case GUI::kListItemDoubleClickedCmd:
+ if (selItem >= 0) {
+ if (!_list->getSelectedString().empty()) {
+ _list->endEditMode();
+ setResult(atoi(_saveList[selItem].save_slot().c_str()));
+ close();
+ }
+ }
+ break;
+ case kChooseCmd:
+ setResult(atoi(_saveList[selItem].save_slot().c_str()));
+ close();
+ break;
+ case GUI::kListSelectionChangedCmd: {
+ updateSelection(true);
+ } break;
+ case kDelCmd:
+ if (selItem >= 0 && _delSupport) {
+ MessageDialog alert("Do you really want to delete this savegame?",
+ "Delete", "Cancel");
+ if (alert.runModal() == GUI::kMessageOK) {
+ (*_plugin)->removeSaveState(_target.c_str(), atoi(_saveList[selItem].save_slot().c_str()));
+
+ setResult(-1);
+ _list->setSelected(-1);
+
+ updateSaveList();
+ updateSelection(true);
+ }
+ }
+ break;
+ case kCloseCmd:
+ setResult(-1);
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void SaveLoadChooser::reflowLayout() {
+ if (g_gui.evaluator()->getVar("scummsaveload_extinfo.visible") == 1 && _thumbnailSupport) {
+ int thumbX = g_gui.evaluator()->getVar("scummsaveload_thumbnail.x");
+ int thumbY = g_gui.evaluator()->getVar("scummsaveload_thumbnail.y");
+ int hPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.hPad");
+ int vPad = g_gui.evaluator()->getVar("scummsaveload_thumbnail.vPad");
+ int thumbH = ((g_system->getHeight() % 200 && g_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1);
+
+ int textLines = 0;
+ if (_saveDateSupport)
+ textLines += 2;
+ if (_playTimeSupport)
+ textLines += 1;
+
+ if (textLines)
+ ++textLines;
+
+ _container->resize(thumbX - hPad, thumbY - vPad, kThumbnailWidth + hPad * 2, thumbH + vPad * 2 + kLineHeight * textLines);
+
+ // Add the thumbnail display
+ _gfxWidget->resize(thumbX, thumbY, kThumbnailWidth, thumbH);
+
+ int height = thumbY + thumbH + kLineHeight;
+
+ if (_saveDateSupport) {
+ _date->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+ height += kLineHeight;
+ _time->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+ height += kLineHeight;
+ }
+
+ if (_playTimeSupport)
+ _playtime->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+
+ _container->clearFlags(GUI::WIDGET_INVISIBLE);
+ _gfxWidget->clearFlags(GUI::WIDGET_INVISIBLE);
+
+ if (_saveDateSupport) {
+ _date->clearFlags(GUI::WIDGET_INVISIBLE);
+ _time->clearFlags(GUI::WIDGET_INVISIBLE);
+ } else {
+ _date->setFlags(GUI::WIDGET_INVISIBLE);
+ _time->setFlags(GUI::WIDGET_INVISIBLE);
+ }
+
+ if (_playTimeSupport)
+ _playtime->clearFlags(GUI::WIDGET_INVISIBLE);
+ else
+ _playtime->setFlags(GUI::WIDGET_INVISIBLE);
+
+ _fillR = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillR");
+ _fillG = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillG");
+ _fillB = g_gui.evaluator()->getVar("scummsaveload_thumbnail.fillB");
+ updateSelection(false);
+ } else {
+ _container->setFlags(GUI::WIDGET_INVISIBLE);
+ _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE);
+ _date->setFlags(GUI::WIDGET_INVISIBLE);
+ _time->setFlags(GUI::WIDGET_INVISIBLE);
+ _playtime->setFlags(GUI::WIDGET_INVISIBLE);
+ }
+
+ Dialog::reflowLayout();
+}
+
+void SaveLoadChooser::updateSelection(bool redraw) {
+ int selItem = _list->getSelected();
+
+ bool isDeletable = _delSupport;
+
+ if (selItem >= 0 && !_list->getSelectedString().empty() && _metaInfoSupport) {
+ SaveStateDescriptor desc = (*_plugin)->querySaveMetaInfos(_target.c_str(), atoi(_saveList[selItem].save_slot().c_str()));
+
+ isDeletable = desc.getBool("is_deletable") && _delSupport;
+
+ if (_thumbnailSupport) {
+ const Graphics::Surface *thumb = desc.getThumbnail();
+ if (thumb) {
+ _gfxWidget->setGfx(thumb);
+ _gfxWidget->useAlpha(256);
+ } else {
+ _gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
+ }
+ }
+
+ if (_saveDateSupport) {
+ Common::String date = "Date: ";
+ if (desc.contains("save_date"))
+ date += desc.getVal("save_date");
+ else
+ date = "No date saved";
+
+ Common::String time = "Time: ";
+ if (desc.contains("save_time"))
+ time += desc.getVal("save_time");
+ else
+ time = "No time saved";
+
+ _date->setLabel(date);
+ _time->setLabel(time);
+ }
+
+ if (_playTimeSupport) {
+ Common::String time = "Playtime: ";
+ if (desc.contains("play_time"))
+ time += desc.getVal("play_time");
+ else
+ time = "No playtime saved";
+
+ _playtime->setLabel(time);
+ }
+ }
+
+
+ // Disable these buttons if nothing is selected, or if an empty
+ // list item is selected.
+ _chooseButton->setEnabled(selItem >= 0 && (!_list->getSelectedString().empty()));
+ // Delete will always be disabled if the engine doesn't support it.
+ _deleteButton->setEnabled(isDeletable && (selItem >= 0) && (!_list->getSelectedString().empty()));
+
+ if (redraw) {
+ _gfxWidget->draw();
+ _date->draw();
+ _time->draw();
+ _playtime->draw();
+ _chooseButton->draw();
+ _deleteButton->draw();
+ }
+}
+
+void SaveLoadChooser::close() {
+ _plugin = 0;
+ _target.clear();
+ _saveList.clear();
+ _list->setList(StringList());
+
+ Dialog::close();
+}
+
+void SaveLoadChooser::updateSaveList() {
+ _saveList = (*_plugin)->listSaves(_target.c_str());
+
+ StringList saveNames;
+ for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
+ Common::String description = x->save_slot();
+ description += ". ";
+ description += x->description();
+
+ saveNames.push_back(description);
+ }
+ _list->setList(saveNames);
+}
#pragma mark -
@@ -499,6 +794,9 @@ LauncherDialog::LauncherDialog()
_startButton =
new ButtonWidget(this, "launcher_start_button", "Start", kStartCmd, 'S');
+ _loadButton =
+ new ButtonWidget(this, "launcher_loadGame_button", "Load", kLoadGameCmd, 'L');
+
// Above the lowest button rows: two more buttons (directly below the list box)
_addButton =
new ButtonWidget(this, "launcher_addGame_button", "Add Game...", kAddGameCmd, 'A');
@@ -526,6 +824,9 @@ LauncherDialog::LauncherDialog()
// Create file browser dialog
_browser = new BrowserDialog("Select directory with game data", true);
+
+ // Create Load dialog
+ _loadDialog = new SaveLoadChooser("Load game:", "Load");
}
void LauncherDialog::selectGame(const String &name) {
@@ -543,6 +844,7 @@ void LauncherDialog::selectGame(const String &name) {
LauncherDialog::~LauncherDialog() {
delete _browser;
+ delete _loadDialog;
}
void LauncherDialog::open() {
@@ -651,9 +953,9 @@ void LauncherDialog::addGame() {
if (_browser->runModal() > 0) {
// User made his choice...
- FilesystemNode dir(_browser->getResult());
- FSList files;
- if (!dir.getChildren(files, FilesystemNode::kListAll)) {
+ Common::FilesystemNode dir(_browser->getResult());
+ Common::FSList files;
+ if (!dir.getChildren(files, Common::FilesystemNode::kListAll)) {
error("browser returned a node that is not a directory: '%s'",
dir.getPath().c_str());
}
@@ -792,6 +1094,37 @@ void LauncherDialog::editGame(int item) {
}
}
+void LauncherDialog::loadGame(int item) {
+ String gameId = ConfMan.get("gameid", _domains[item]);
+ if (gameId.empty())
+ gameId = _domains[item];
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ String target = _domains[item];
+ target.toLowercase();
+
+ if (plugin) {
+ if ((*plugin)->hasFeature(MetaEngine::kSupportsListSaves) &&
+ (*plugin)->hasFeature(MetaEngine::kSupportsDirectLoad)) {
+ int slot = _loadDialog->runModal(plugin, target);
+ if (slot >= 0) {
+ ConfMan.setActiveDomain(_domains[item]);
+ ConfMan.setInt("save_slot", slot, Common::ConfigManager::kTransientDomain);
+ close();
+ }
+ } else {
+ MessageDialog dialog
+ ("This game does not support loading games from the launcher.", "OK");
+ dialog.runModal();
+ }
+ } else {
+ MessageDialog dialog("ScummVM could not find any engine capable of running the selected game!", "OK");
+ dialog.runModal();
+ }
+}
+
void LauncherDialog::handleKeyDown(Common::KeyState state) {
Dialog::handleKeyDown(state);
updateButtons();
@@ -815,6 +1148,9 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kEditGameCmd:
editGame(item);
break;
+ case kLoadGameCmd:
+ loadGame(item);
+ break;
case kOptionsCmd: {
GlobalOptionsDialog options;
options.runModal();
@@ -863,6 +1199,10 @@ void LauncherDialog::updateButtons() {
_removeButton->setEnabled(enable);
_removeButton->draw();
}
+ if (enable != _loadButton->isEnabled()) {
+ _loadButton->setEnabled(enable);
+ _loadButton->draw();
+ }
// Update the label of the "Add" button depending on whether shift is pressed or not
int modifiers = g_system->getEventManager()->getModifierState();
diff --git a/gui/launcher.h b/gui/launcher.h
index a9d09bf109..1b2b0a354e 100644
--- a/gui/launcher.h
+++ b/gui/launcher.h
@@ -26,7 +26,7 @@
#define LAUNCHER_DIALOG_H
#include "gui/dialog.h"
-#include "base/game.h"
+#include "engines/game.h"
#include "common/str.h"
namespace GUI {
@@ -34,11 +34,10 @@ namespace GUI {
class BrowserDialog;
class ListWidget;
class GraphicsWidget;
-
+class SaveLoadChooser;
Common::String addGameToConf(const GameDescriptor &result);
-
class LauncherDialog : public Dialog {
typedef Common::String String;
typedef Common::StringList StringList;
@@ -55,6 +54,7 @@ protected:
ListWidget *_list;
ButtonWidget *_addButton;
Widget *_startButton;
+ Widget *_loadButton;
Widget *_editButton;
Widget *_removeButton;
#ifndef DISABLE_FANCY_THEMES
@@ -62,6 +62,7 @@ protected:
#endif
StringList _domains;
BrowserDialog *_browser;
+ SaveLoadChooser *_loadDialog;
virtual void reflowLayout();
@@ -73,7 +74,8 @@ protected:
virtual void addGame();
void removeGame(int item);
void editGame(int item);
-
+ void loadGame(int item);
+
void selectGame(const String &name);
};
diff --git a/gui/massadd.cpp b/gui/massadd.cpp
index 6842466ad9..c34c190776 100644
--- a/gui/massadd.cpp
+++ b/gui/massadd.cpp
@@ -58,7 +58,7 @@ enum {
-MassAddDialog::MassAddDialog(const FilesystemNode &startDir)
+MassAddDialog::MassAddDialog(const Common::FilesystemNode &startDir)
: Dialog("massadddialog"),
_dirsScanned(0),
_okButton(0),
@@ -156,10 +156,10 @@ void MassAddDialog::handleTickle() {
// Perform a breadth-first scan of the filesystem.
while (!_scanStack.empty() && (g_system->getMillis() - t) < kMaxScanTime) {
- FilesystemNode dir = _scanStack.pop();
+ Common::FilesystemNode dir = _scanStack.pop();
- FSList files;
- if (!dir.getChildren(files, FilesystemNode::kListAll)) {
+ Common::FSList files;
+ if (!dir.getChildren(files, Common::FilesystemNode::kListAll)) {
error("browser returned a node that is not a directory: '%s'",
dir.getPath().c_str());
}
@@ -206,7 +206,7 @@ void MassAddDialog::handleTickle() {
// Recurse into all subdirs
- for (FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
+ for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
if (file->isDirectory()) {
_scanStack.push(*file);
}
diff --git a/gui/massadd.h b/gui/massadd.h
index e0eff75c64..733559cf37 100644
--- a/gui/massadd.h
+++ b/gui/massadd.h
@@ -38,14 +38,14 @@ class StaticTextWidget;
class MassAddDialog : public Dialog {
public:
- MassAddDialog(const FilesystemNode &startDir);
+ MassAddDialog(const Common::FilesystemNode &startDir);
//void open();
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
void handleTickle();
private:
- Common::Stack<FilesystemNode> _scanStack;
+ Common::Stack<Common::FilesystemNode> _scanStack;
GameList _games;
/**
diff --git a/gui/newgui.cpp b/gui/newgui.cpp
index 6c42d8e9b2..4afc59367b 100644
--- a/gui/newgui.cpp
+++ b/gui/newgui.cpp
@@ -26,6 +26,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/util.h"
+#include "engines/engine.h"
#include "graphics/cursorman.h"
#include "gui/newgui.h"
#include "gui/dialog.h"
@@ -73,9 +74,9 @@ void GuiObject::reflowLayout() {
error("Widget <%s> has x + w > %d (%d)", _name.c_str(), g_system->getOverlayWidth(), _x + _w);
if (_y < 0)
error("Widget <%s> has y < 0", _name.c_str());
- if (_y >= g_system->getOverlayWidth())
+ if (_y >= g_system->getOverlayHeight())
error("Widget <%s> has y > %d", _name.c_str(), g_system->getOverlayHeight());
- if (_y + _h > g_system->getOverlayWidth())
+ if (_y + _h > g_system->getOverlayHeight())
error("Widget <%s> has y + h > %d (%d)", _name.c_str(), g_system->getOverlayHeight(), _y + _h);
}
}
@@ -256,7 +257,7 @@ void NewGui::runLoop() {
Common::Event event;
while (eventMan->pollEvent(event)) {
- if (activeDialog != getTopDialog() && event.type != Common::EVENT_QUIT && event.type != Common::EVENT_SCREEN_CHANGED)
+ if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED)
continue;
Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y);
@@ -314,7 +315,8 @@ void NewGui::runLoop() {
activeDialog->handleMouseWheel(mouse.x, mouse.y, 1);
break;
case Common::EVENT_QUIT:
- _system->quit();
+ if (!g_engine)
+ _system->quit();
return;
case Common::EVENT_SCREEN_CHANGED:
screenChange();
diff --git a/gui/options.cpp b/gui/options.cpp
index d6f5306ce2..335d4bc3d0 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -835,7 +835,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
BrowserDialog browser("Select directory for savegames", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
if (dir.isWritable()) {
_savePath->setLabel(dir.getPath());
} else {
@@ -851,7 +851,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
BrowserDialog browser("Select directory for GUI themes", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
_themePath->setLabel(dir.getPath());
draw();
}
@@ -861,7 +861,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
BrowserDialog browser("Select directory for extra files", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
_extraPath->setLabel(dir.getPath());
draw();
}
@@ -872,7 +872,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
BrowserDialog browser("Select directory for plugins", true);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode dir(browser.getResult());
+ Common::FilesystemNode dir(browser.getResult());
_pluginsPath->setLabel(dir.getPath());
draw();
}
@@ -883,7 +883,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
BrowserDialog browser("Select SoundFont", false);
if (browser.runModal() > 0) {
// User made his choice...
- FilesystemNode file(browser.getResult());
+ Common::FilesystemNode file(browser.getResult());
_soundFont->setLabel(file.getPath());
if (!file.getPath().empty() && (file.getPath() != "None"))
diff --git a/gui/theme-config.cpp b/gui/theme-config.cpp
index acb5660db8..81e0a5c1d7 100644
--- a/gui/theme-config.cpp
+++ b/gui/theme-config.cpp
@@ -95,6 +95,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
+"scummsaveload_delete=prev.x2 prev.y prev.w prev.h\n"
"scummsaveload_extinfo.visible=false\n"
"\n"
"# MM NES resolution\n"
@@ -118,6 +119,7 @@ const char *Theme::_defaultConfigINI =
"def_aboutXOff=8\n"
"def_aboutYOff=5\n"
"def_aboutOuterBorder=80\n"
+"def_globalmainHOffset=52\n"
"def_scummmainHOffset=12\n"
"def_scummmainVSpace=7\n"
"def_scummmainVAddOff=3\n"
@@ -171,10 +173,11 @@ const char *Theme::_defaultConfigINI =
"launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"top=(top - buttonHeight * 2)\n"
-"numButtons=3\n"
+"numButtons=4\n"
"space=10\n"
"butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)\n"
-"launcher_addGame_button=hBorder top butWidth buttonHeight\n"
+"launcher_loadGame_button=hBorder top butWidth buttonHeight\n"
+"launcher_addGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_editGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_removeGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_list=hBorder (kLineHeight + 16) (w - 2 * hBorder) (top - kLineHeight - 20)\n"
@@ -371,6 +374,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail.fillB=0\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
+"scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h\n"
"scummsaveload_extinfo.visible=true\n"
"\n"
"# Keymapper remap dialog\n"
@@ -490,6 +494,31 @@ const char *Theme::_defaultConfigINI =
"smH=(smY + scummmainVSpace)\n"
"scummmain=((w - smW) / 2) ((h - smH) / 2) smW smH\n"
"\n"
+"#### Global Main Menu Dialog"
+"[globalmain]\n"
+"# note that globalmain size depends on overall height\n"
+"hBorder=10\n"
+"gmW=(scummmainButtonWidth + (2 * scummmainHOffset) + 80)\n"
+"global_title=hBorder 8 (gmW - 2 * hBorder) kLineHeight\n"
+"global_title.align=kTextAlignCenter\n"
+"global_version=hBorder 25 (gmW - 2 * hBorder) kLineHeight\n"
+"global_version.align=kTextAlignCenter\n"
+"gmY=((scummmainVSpace * 7)+ scummmainVAddOff)\n"
+"globalmain_resume=globalmainHOffset gmY scummmainButtonWidth scummmainButtonHeight\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmY=(gmY + scummmainVSpace)\n"
+"globalmain_options=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"globalmain_about=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmY=(gmY + scummmainVSpace)\n"
+"globalmain_rtl=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"globalmain_quit=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmH=(gmY + scummmainVSpace)\n"
+"globalmain=((w - gmW) / 2) ((h - gmH) / 2) gmW gmH\n"
+"\n"
"# PSP GUI\n"
"[480x272]\n"
"def_buttonWidth=100\n"
diff --git a/gui/theme.cpp b/gui/theme.cpp
index c8501c4f91..8928d2f467 100644
--- a/gui/theme.cpp
+++ b/gui/theme.cpp
@@ -24,7 +24,9 @@
#include "gui/theme.h"
#include "gui/eval.h"
+#include "common/file.h"
+#include "common/archive.h"
#include "common/unzip.h"
namespace GUI {
@@ -68,24 +70,11 @@ const Graphics::Font *Theme::loadFont(const char *filename) {
return font;
#ifdef USE_ZLIB
- unzFile zipFile = unzOpen((_stylefile + ".zip").c_str());
- if (zipFile && unzLocateFile(zipFile, cacheFilename.c_str(), 2) == UNZ_OK) {
- unz_file_info fileInfo;
- unzOpenCurrentFile(zipFile);
- unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- uint8 *buffer = new uint8[fileInfo.uncompressed_size+1];
- assert(buffer);
- memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8));
- unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(zipFile);
- Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size+1);
-
- font = Graphics::NewFont::loadFromCache(stream);
-
- delete[] buffer;
- buffer = 0;
+ Common::ZipArchive zipArchive(_stylefile + ".zip");
+ if (zipArchive.hasFile(cacheFilename)) {
+ Common::FilePtr stream(zipArchive.openFile(cacheFilename));
+ font = Graphics::NewFont::loadFromCache(*stream.get());
}
- unzClose(zipFile);
#endif
if (font)
return font;
@@ -98,24 +87,11 @@ const Graphics::Font *Theme::loadFont(const char *filename) {
#ifdef USE_ZLIB
if (!font) {
- unzFile zipFile = unzOpen((_stylefile + ".zip").c_str());
- if (zipFile && unzLocateFile(zipFile, filename, 2) == UNZ_OK) {
- unz_file_info fileInfo;
- unzOpenCurrentFile(zipFile);
- unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- uint8 *buffer = new uint8[fileInfo.uncompressed_size+1];
- assert(buffer);
- memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8));
- unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(zipFile);
- Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size+1);
-
- font = Graphics::NewFont::loadFont(stream);
-
- delete[] buffer;
- buffer = 0;
+ Common::ZipArchive zipArchive(_stylefile + ".zip");
+ if (zipArchive.hasFile(filename)) {
+ Common::FilePtr stream(zipArchive.openFile(filename));
+ font = Graphics::NewFont::loadFont(*stream.get());
}
- unzClose(zipFile);
}
#endif
@@ -157,37 +133,20 @@ bool Theme::loadConfigFile(const Common::String &stylefile) {
if (ConfMan.hasKey("extrapath"))
Common::File::addDefaultDirectoryRecursive(ConfMan.get("extrapath"));
- if (!_configFile.loadFromFile(stylefile + ".ini")) {
+ if (_configFile.loadFromFile(stylefile + ".ini"))
+ return true;
+
#ifdef USE_ZLIB
- // Maybe find a nicer solution to this
- unzFile zipFile = unzOpen((stylefile + ".zip").c_str());
- if (zipFile && unzLocateFile(zipFile, (stylefile + ".ini").c_str(), 2) == UNZ_OK) {
- unz_file_info fileInfo;
- unzOpenCurrentFile(zipFile);
- unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- uint8 *buffer = new uint8[fileInfo.uncompressed_size+1];
- assert(buffer);
- memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8));
- unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(zipFile);
- Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size+1);
- if (!_configFile.loadFromStream(stream)) {
- unzClose(zipFile);
- return false;
- }
- delete[] buffer;
- buffer = 0;
- } else {
- unzClose(zipFile);
- return false;
- }
- unzClose(zipFile);
-#else
- return false;
-#endif
+ // Maybe find a nicer solution to this
+ Common::ZipArchive zipArchive(stylefile + ".zip");
+ if (zipArchive.hasFile(stylefile + ".ini")) {
+ Common::FilePtr stream(zipArchive.openFile(stylefile + ".ini"));
+ if (_configFile.loadFromStream(*stream.get()))
+ return true;
}
+#endif
- return true;
+ return false;
}
bool Theme::themeConfigUseable(const Common::String &stylefile, const Common::String &style, Common::String *cStyle, Common::ConfigFile *cfg) {
@@ -209,30 +168,16 @@ bool Theme::themeConfigUseable(const Common::String &stylefile, const Common::St
if (!file.open(stylefile + ".ini")) {
#ifdef USE_ZLIB
// Maybe find a nicer solution to this
- unzFile zipFile = unzOpen((stylefile + ".zip").c_str());
- if (zipFile && unzLocateFile(zipFile, (stylefile + ".ini").c_str(), 2) == UNZ_OK) {
+ Common::ZipArchive zipArchive(stylefile + ".zip");
+ if (zipArchive.hasFile(stylefile + ".ini")) {
if (!style.empty() || cStyle || cfg) {
- unz_file_info fileInfo;
- unzOpenCurrentFile(zipFile);
- unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- uint8 *buffer = new uint8[fileInfo.uncompressed_size+1];
- assert(buffer);
- memset(buffer, 0, (fileInfo.uncompressed_size+1)*sizeof(uint8));
- unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
- unzCloseCurrentFile(zipFile);
- Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size+1);
- if (!cfg->loadFromStream(stream)) {
- unzClose(zipFile);
+ Common::FilePtr stream(zipArchive.openFile(stylefile + ".ini"));
+ if (!cfg->loadFromStream(*stream.get()))
return false;
- }
- delete[] buffer;
- buffer = 0;
}
} else {
- unzClose(zipFile);
return false;
}
- unzClose(zipFile);
#else
return false;
#endif
diff --git a/gui/theme.h b/gui/theme.h
index 4f61609fbd..c5a412e286 100644
--- a/gui/theme.h
+++ b/gui/theme.h
@@ -28,13 +28,12 @@
#include "common/system.h"
#include "common/rect.h"
#include "common/str.h"
-#include "common/file.h"
#include "common/config-file.h"
#include "graphics/surface.h"
#include "graphics/fontman.h"
-#define THEME_VERSION 23
+#define THEME_VERSION 24
namespace GUI {
@@ -357,7 +356,8 @@ public:
//! Special image ids for images used in the GUI
enum kThemeImages {
- kImageLogo = 0 //! ScummVM Logo used in the launcher
+ kImageLogo = 0, //! ScummVM Logo used in the launcher
+ kImageLogoSmall //! ScummVM logo used in the GMM
};
/**
diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp
index 98e6df8565..bf718d5e4a 100644
--- a/gui/themebrowser.cpp
+++ b/gui/themebrowser.cpp
@@ -141,16 +141,16 @@ void ThemeBrowser::addDir(ThList &list, const Common::String &dir, int level) {
if (level < 0)
return;
- FilesystemNode node(dir);
+ Common::FilesystemNode node(dir);
if (!node.exists() || !node.isReadable())
return;
- FSList fslist;
- if (!node.getChildren(fslist, FilesystemNode::kListAll))
+ Common::FSList fslist;
+ if (!node.getChildren(fslist, Common::FilesystemNode::kListAll))
return;
- for (FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) {
+ for (Common::FSList::const_iterator i = fslist.begin(); i != fslist.end(); ++i) {
if (i->isDirectory()) {
addDir(list, i->getPath(), level-1);
} else {
@@ -171,7 +171,7 @@ void ThemeBrowser::addDir(ThList &list, const Common::String &dir, int level) {
}
}
-bool ThemeBrowser::isTheme(const FilesystemNode &node, Entry &out) {
+bool ThemeBrowser::isTheme(const Common::FilesystemNode &node, Entry &out) {
Common::ConfigFile cfg;
Common::String type;
diff --git a/gui/themebrowser.h b/gui/themebrowser.h
index 9351648d24..e16a329c0e 100644
--- a/gui/themebrowser.h
+++ b/gui/themebrowser.h
@@ -58,7 +58,7 @@ private:
void updateListing();
void addDir(ThList &list, const Common::String &dir, int level = 4);
- bool isTheme(const FilesystemNode &node, Entry &out);
+ bool isTheme(const Common::FilesystemNode &node, Entry &out);
};
} // end of namespace GUI
diff --git a/gui/themes/classic080.ini b/gui/themes/classic080.ini
index b5c911bada..4138e24536 100644
--- a/gui/themes/classic080.ini
+++ b/gui/themes/classic080.ini
@@ -1,7 +1,7 @@
# $URL$
# $Id$
[theme]
-version=23
+version=24
type=classic
name=Classic (ScummVM 0.8.0)
@@ -82,13 +82,14 @@ hBorder=10
launcher_version=hBorder 8 (w - 2 * hBorder) kLineHeight
launcher_version.align=kTextAlignCenter
top=(h - 8 - buttonHeight)
-numButtons=4
+numButtons=3
space=8
butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)
launcher_quit_button=hBorder top butWidth buttonHeight
launcher_about_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h
+launcher_loadGame_button=(prev.x2 + space) prev.y prev.w prev.h
top=(top - buttonHeight * 2)
numButtons=3
space=10
@@ -289,6 +290,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################
@@ -441,6 +443,7 @@ scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=false
# MM NES resolution
diff --git a/gui/themes/modern.ini b/gui/themes/modern.ini
index 87ef0bcbb9..e1712c5608 100644
--- a/gui/themes/modern.ini
+++ b/gui/themes/modern.ini
@@ -1,7 +1,7 @@
# $URL$
# $Id$
[theme]
-version=23
+version=24
type=modern
name=Modern Style
@@ -67,6 +67,7 @@ pix_edittext_bkgd_left="button_bkgd_left.bmp"
pix_edittext_bkgd_bkgd="button_bkgd.bmp"
pix_theme_logo="logo.bmp"
+pix_theme_logo_small="logo_small.bmp"
pix_cursor_image="cursor.bmp"
@@ -250,6 +251,7 @@ space1=20
space2=5
launcher_list=insetX insetY insetW insetH
launcher_start_button=(prev.x2 + 17) prev.y buttonWidth buttonHeight
+launcher_loadGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_addGame_button=prev.x (prev.y2 + space1) prev.w prev.h
launcher_editGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_removeGame_button=prev.x (prev.y2 + space2) prev.w prev.h
@@ -259,6 +261,30 @@ launcher_quit_button=prev.x (prev.y2 + space1) prev.w prev.h
use=scummmain
+#### Global Main Menu Dialog
+# note that globalmain size depends on overall height
+hBorder=10
+gmW=(scummmainButtonWidth + (2 * scummmainHOffset) + 80)
+global_logo=((gmW - 142) / 2) scummmainVSpace 142 40
+global_logo.visible=true
+global_version=hBorder (prev.y + prev.h) (gmW - 2 * hBorder) kLineHeight
+global_version.align=kTextAlignCenter
+gmY=(prev.y + prev.h + scummmainVAddOff)
+globalmain_resume=globalmainHOffset gmY scummmainButtonWidth scummmainButtonHeight
+gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
+gmY=(gmY + scummmainVSpace)
+globalmain_options=prev.x gmY prev.w prev.h
+gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
+globalmain_about=prev.x gmY prev.w prev.h
+gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
+gmY=(gmY + scummmainVSpace)
+globalmain_rtl=prev.x gmY prev.w prev.h
+gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
+globalmain_quit=prev.x gmY prev.w prev.h
+gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)
+gmH=(gmY + scummmainVSpace)
+globalmain=((w - gmW) / 2) ((h - gmH) / 2) gmW gmH
+
### global options
globaloptions=insetX insetY insetW insetH
set_parent=globaloptions
@@ -456,6 +482,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################
diff --git a/gui/themes/modern.zip b/gui/themes/modern.zip
index 739c6d23ac..329e3a2c1b 100644
--- a/gui/themes/modern.zip
+++ b/gui/themes/modern.zip
Binary files differ
diff --git a/gui/widget.cpp b/gui/widget.cpp
index e9afc30301..31f76eac6f 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -363,8 +363,7 @@ void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
return;
// TODO: add conversion to OverlayColor
- _gfx.create(gfx->w, gfx->h, gfx->bytesPerPixel);
- memcpy(_gfx.pixels, gfx->pixels, gfx->h * gfx->pitch);
+ _gfx.copyFrom(*gfx);
}
void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) {
diff --git a/ports.mk b/ports.mk
index 80efcfacc4..00a272f748 100644
--- a/ports.mk
+++ b/ports.mk
@@ -10,7 +10,7 @@
#
install: all
$(INSTALL) -d "$(DESTDIR)$(BINDIR)"
- $(INSTALL) -c -s -m 755 "$(srcdir)/scummvm$(EXEEXT)" "$(DESTDIR)$(BINDIR)/scummvm$(EXEEXT)"
+ $(INSTALL) -c -s -m 755 "./scummvm$(EXEEXT)" "$(DESTDIR)$(BINDIR)/scummvm$(EXEEXT)"
$(INSTALL) -d "$(DESTDIR)$(MANDIR)/man6/"
$(INSTALL) -c -m 644 "$(srcdir)/dists/scummvm.6" "$(DESTDIR)$(MANDIR)/man6/scummvm.6"
$(INSTALL) -d "$(DESTDIR)$(PREFIX)/share/pixmaps/"
diff --git a/sound/adpcm.cpp b/sound/adpcm.cpp
index ad072af360..a30cf9c61e 100644
--- a/sound/adpcm.cpp
+++ b/sound/adpcm.cpp
@@ -38,7 +38,7 @@ class ADPCMInputStream : public AudioStream {
private:
Common::SeekableReadStream *_stream;
bool _disposeAfterUse;
- uint32 _endpos;
+ int32 _endpos;
int _channels;
typesADPCM _type;
uint32 _blockAlign;
diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp
index 343d5bc440..8fc9100926 100644
--- a/sound/audiocd.cpp
+++ b/sound/audiocd.cpp
@@ -29,7 +29,6 @@
#include "sound/vorbis.h"
#include "sound/flac.h"
#include "engines/engine.h"
-#include "common/file.h"
#include "common/util.h"
#include "common/system.h"
diff --git a/sound/flac.cpp b/sound/flac.cpp
index f058d2dc6f..7b46f0660f 100644
--- a/sound/flac.cpp
+++ b/sound/flac.cpp
@@ -27,7 +27,7 @@
#ifdef USE_FLAC
-#include "common/file.h"
+#include "common/stream.h"
#include "common/util.h"
#include "sound/audiostream.h"
@@ -72,9 +72,6 @@ typedef FLAC__StreamDecoder FLAC__SeekableStreamDecoder;
#endif
-using Common::File;
-
-
namespace Audio {
#pragma mark -
@@ -149,7 +146,7 @@ public:
bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; }
protected:
- uint getChannels() const { return MIN(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }
+ uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }
bool allocateBuffer(uint minSamples);
@@ -659,7 +656,7 @@ inline ::FLAC__StreamDecoderWriteStatus FlacInputStream::callbackWrite(const ::F
inline ::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callbackSeek(FLAC__uint64 absoluteByteOffset) {
_inStream->seek(absoluteByteOffset, SEEK_SET);
- const bool result = (absoluteByteOffset == _inStream->pos());
+ const bool result = (absoluteByteOffset == (FLAC__uint64)_inStream->pos());
#ifdef LEGACY_FLAC
return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
diff --git a/sound/flac.h b/sound/flac.h
index 5c825847b6..8a51441afd 100644
--- a/sound/flac.h
+++ b/sound/flac.h
@@ -31,7 +31,6 @@
#ifdef USE_FLAC
namespace Common {
- class File;
class SeekableReadStream;
}
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index 358d42d751..473612f6bc 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -46,7 +46,11 @@ static const MidiDriverDescription s_musicDrivers[] = {
{"alsa", "ALSA", MD_ALSA, MDT_MIDI},
#endif
-#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__)
+#if defined(__MINT__)
+ {"stmidi", "Atari ST MIDI", MD_STMIDI, MDT_MIDI},
+#endif
+
+#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) && !defined(__MINT__)
{"seq", "SEQ", MD_SEQ, MDT_MIDI},
#endif
@@ -247,7 +251,10 @@ MidiDriver *MidiDriver::createMidi(int midiDriver) {
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
case MD_WINDOWS: return MidiDriver_WIN_create(g_system->getMixer());
#endif
-#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__)
+#if defined(__MINT__)
+ case MD_STMIDI: return MidiDriver_STMIDI_create(g_system->getMixer());
+#endif
+#if defined(UNIX) && !defined(__BEOS__) && !defined(MACOSX) && !defined(__MAEMO__) && !defined(__MINT__)
case MD_SEQ: return MidiDriver_SEQ_create(g_system->getMixer());
#endif
#if defined(UNIX)
diff --git a/sound/mididrv.h b/sound/mididrv.h
index 12513268a8..9d5a7d4407 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -51,6 +51,9 @@ enum MidiDriverType {
// Windows
MD_WINDOWS,
+ // Atari ST
+ MD_STMIDI,
+
// Linux
MD_ALSA,
MD_SEQ,
@@ -271,6 +274,7 @@ public:
extern MidiDriver *MidiDriver_NULL_create(Audio::Mixer *mixer);
extern MidiDriver *MidiDriver_ADLIB_create(Audio::Mixer *mixer);
extern MidiDriver *MidiDriver_WIN_create(Audio::Mixer *mixer);
+extern MidiDriver *MidiDriver_STMIDI_create(Audio::Mixer *mixer);
extern MidiDriver *MidiDriver_SEQ_create(Audio::Mixer *mixer);
extern MidiDriver *MidiDriver_TIMIDITY_create(Audio::Mixer *mixer);
extern MidiDriver *MidiDriver_QT_create(Audio::Mixer *mixer);
diff --git a/sound/midiparser.h b/sound/midiparser.h
index d5209acb10..304a9d9f82 100644
--- a/sound/midiparser.h
+++ b/sound/midiparser.h
@@ -352,6 +352,8 @@ public:
};
public:
+ typedef void (*XMidiCallbackProc)(byte eventData, void *refCon);
+
MidiParser();
virtual ~MidiParser() { allNotesOff(); }
@@ -370,8 +372,10 @@ public:
uint32 getPPQN() { return _ppqn; }
virtual uint32 getTick() { return _position._play_tick; }
+ static void defaultXMidiCallback(byte eventData, void *refCon);
+
static MidiParser *createParser_SMF();
- static MidiParser *createParser_XMIDI();
+ static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0);
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
};
diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp
index 7cf114dcc6..0180322927 100644
--- a/sound/midiparser_xmidi.cpp
+++ b/sound/midiparser_xmidi.cpp
@@ -46,13 +46,16 @@ protected:
Loop _loop[4];
int _loopCount;
+ XMidiCallbackProc _callbackProc;
+ void *_callbackData;
+
protected:
uint32 readVLQ2(byte * &data);
void resetTracking();
void parseNextEvent(EventInfo &info);
public:
- MidiParser_XMIDI() : _inserted_delta(0) {}
+ MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _inserted_delta(0), _callbackProc(proc), _callbackData(data) {}
~MidiParser_XMIDI() { }
bool loadMusic(byte *data, uint32 size);
@@ -103,23 +106,22 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
info.basic.param1 = *(_position._play_pos++);
info.basic.param2 = *(_position._play_pos++);
+ // This isn't a full XMIDI implementation, but it should
+ // hopefully be "good enough" for most things.
+
+ switch (info.basic.param1) {
// Simplified XMIDI looping.
- //
- // I would really like to turn the loop events into some sort
- // of NOP event (perhaps a dummy META event?), but for now we
- // just pass them on to the MIDI driver. That has worked in the
- // past, so it shouldn't cause any actual damage...
-
- if (info.basic.param1 == 0x74) {
- // XMIDI_CONTROLLER_FOR_LOOP
- byte *pos = _position._play_pos;
- if (_loopCount < ARRAYSIZE(_loop) - 1)
- _loopCount++;
-
- _loop[_loopCount].pos = pos;
- _loop[_loopCount].repeat = info.basic.param2;
- } else if (info.basic.param1 == 0x75) {
- // XMIDI_CONTROLLER_NEXT_BREAK
+ case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP
+ byte *pos = _position._play_pos;
+ if (_loopCount < ARRAYSIZE(_loop) - 1)
+ _loopCount++;
+
+ _loop[_loopCount].pos = pos;
+ _loop[_loopCount].repeat = info.basic.param2;
+ break;
+ }
+
+ case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK
if (_loopCount >= 0) {
if (info.basic.param2 < 64) {
// End the current loop.
@@ -133,7 +135,26 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
}
}
}
+ break;
+
+ case 0x77: // XMIDI_CONTROLLER_CALLBACK_TRIG
+ if (_callbackProc)
+ _callbackProc(info.basic.param2, _callbackData);
+ break;
+
+ default:
+ if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) {
+ warning("Unsupported XMIDI controller %d (0x%2x)",
+ info.basic.param1, info.basic.param1);
+ }
+ break;
}
+
+ // Should we really keep passing the XMIDI controller events to
+ // the MIDI driver, or should we turn them into some kind of
+ // NOP events? (Dummy meta events, perhaps?) Ah well, it has
+ // worked so far, so it shouldn't cause any damage...
+
break;
case 0xF: // Meta or SysEx event
@@ -333,4 +354,10 @@ void MidiParser_XMIDI::resetTracking() {
_inserted_delta = 0;
}
-MidiParser *MidiParser::createParser_XMIDI() { return new MidiParser_XMIDI; }
+void MidiParser::defaultXMidiCallback(byte eventData, void *data) {
+ warning("MidiParser: defaultXMidiCallback(%d)", eventData);
+}
+
+MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) {
+ return new MidiParser_XMIDI(proc, data);
+}
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index 27e031f108..824143d829 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/file.h"
#include "common/util.h"
#include "common/system.h"
diff --git a/sound/mods/infogrames.cpp b/sound/mods/infogrames.cpp
index 97987b037a..a5b3ea1f35 100644
--- a/sound/mods/infogrames.cpp
+++ b/sound/mods/infogrames.cpp
@@ -25,6 +25,7 @@
#include "sound/mods/infogrames.h"
#include "common/endian.h"
+#include "common/file.h"
namespace Audio {
@@ -50,12 +51,20 @@ void Infogrames::Instruments::init() {
_sampleData = 0;
}
+bool Infogrames::Instruments::load(const char *ins) {
+ Common::File f;
+
+ if (f.open(ins))
+ return load(f);
+ return false;
+}
+
bool Infogrames::Instruments::load(Common::SeekableReadStream &ins) {
int i;
- uint32 fsize;
- uint32 offset[32];
- uint32 offsetRepeat[32];
- uint32 dataOffset;
+ int32 fsize;
+ int32 offset[32];
+ int32 offsetRepeat[32];
+ int32 dataOffset;
unload();
@@ -191,6 +200,14 @@ void Infogrames::reset() {
_chn[i].cmdBlockIndices = 0;
}
+bool Infogrames::load(const char *dum) {
+ Common::File f;
+
+ if (f.open(dum))
+ return load(f);
+ return false;
+}
+
bool Infogrames::load(Common::SeekableReadStream &dum) {
int subSong = 0;
int i;
diff --git a/sound/mods/infogrames.h b/sound/mods/infogrames.h
index 572c5a6426..d44ea0475c 100644
--- a/sound/mods/infogrames.h
+++ b/sound/mods/infogrames.h
@@ -28,7 +28,6 @@
#include "sound/mods/paula.h"
#include "common/stream.h"
-#include "common/file.h"
namespace Audio {
@@ -46,13 +45,7 @@ public:
~Instruments();
bool load(Common::SeekableReadStream &ins);
- bool load(const char *ins) {
- Common::File f;
-
- if (f.open(ins))
- return load(f);
- return false;
- }
+ bool load(const char *ins);
void unload(void);
uint8 getCount(void) const { return _count; }
@@ -82,13 +75,7 @@ public:
void setRepeating (int32 repCount) { _repCount = repCount; }
bool load(Common::SeekableReadStream &dum);
- bool load(const char *dum) {
- Common::File f;
-
- if (f.open(dum))
- return load(f);
- return false;
- }
+ bool load(const char *dum);
void unload(void);
void restart(void) {
if (_data) {
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
index 70467bdb39..0249032e2f 100644
--- a/sound/mp3.cpp
+++ b/sound/mp3.cpp
@@ -27,7 +27,7 @@
#ifdef USE_MAD
-#include "common/file.h"
+#include "common/stream.h"
#include "common/util.h"
#include "sound/audiocd.h"
diff --git a/sound/mp3.h b/sound/mp3.h
index d544e60e0e..a27fc9dec5 100644
--- a/sound/mp3.h
+++ b/sound/mp3.h
@@ -31,7 +31,6 @@
#ifdef USE_MAD
namespace Common {
- class File;
class SeekableReadStream;
}
diff --git a/sound/softsynth/mt32.cpp b/sound/softsynth/mt32.cpp
index 360ef4539d..3e3f9d91ff 100644
--- a/sound/softsynth/mt32.cpp
+++ b/sound/softsynth/mt32.cpp
@@ -96,12 +96,9 @@ public:
size_t read(void *in, size_t size) {
return _in.read(in, size);
}
- bool readLine(char *in, size_t size) {
- return _in.readLine(in, size) != NULL;
- }
bool readBit8u(MT32Emu::Bit8u *in) {
byte b = _in.readByte();
- if (_in.eof())
+ if (_in.eos())
return false;
*in = b;
return true;
@@ -114,7 +111,7 @@ public:
return !_out.ioFailed();
}
bool isEOF() {
- return _in.isOpen() ? _in.eof() : _out.eof();
+ return _in.isOpen() && _in.eos();
}
};
diff --git a/sound/softsynth/mt32/mt32_file.cpp b/sound/softsynth/mt32/mt32_file.cpp
index 86cb29fd49..f4eba73d33 100644
--- a/sound/softsynth/mt32/mt32_file.cpp
+++ b/sound/softsynth/mt32/mt32_file.cpp
@@ -44,10 +44,6 @@ namespace MT32Emu {
return fread(in, 1, size, fp);
}
- bool ANSIFile::readLine(char *in, size_t size) {
- return fgets(in, (int)size, fp) != NULL;
- }
-
bool ANSIFile::readBit8u(Bit8u *in) {
int c = fgetc(fp);
if (c == EOF)
diff --git a/sound/softsynth/mt32/mt32_file.h b/sound/softsynth/mt32/mt32_file.h
index 5f05c9e9ae..27c8ccbe46 100644
--- a/sound/softsynth/mt32/mt32_file.h
+++ b/sound/softsynth/mt32/mt32_file.h
@@ -35,7 +35,6 @@ public:
virtual ~File() {}
virtual void close() = 0;
virtual size_t read(void *in, size_t size) = 0;
- virtual bool readLine(char *in, size_t size) = 0;
virtual bool readBit8u(Bit8u *in) = 0;
virtual bool readBit16u(Bit16u *in);
virtual bool readBit32u(Bit32u *in);
@@ -55,7 +54,6 @@ public:
bool open(const char *filename, OpenMode mode);
void close();
size_t read(void *in, size_t size);
- bool readLine(char *in, size_t size);
bool readBit8u(Bit8u *in);
size_t write(const void *out, size_t size);
bool writeBit8u(Bit8u out);
diff --git a/sound/softsynth/mt32/partial.cpp b/sound/softsynth/mt32/partial.cpp
index 1aab2a8de7..2866c7757d 100644
--- a/sound/softsynth/mt32/partial.cpp
+++ b/sound/softsynth/mt32/partial.cpp
@@ -25,7 +25,7 @@
#include "mt32emu.h"
-#if defined(MACOSX) || defined(__solaris__)
+#if defined(MACOSX) || defined(SOLARIS)
// Older versions of Mac OS X didn't supply a powf function, so using it
// will cause a binary incompatibility when trying to run a binary built
// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
diff --git a/sound/softsynth/mt32/synth.cpp b/sound/softsynth/mt32/synth.cpp
index 785e8098c7..366da50d01 100644
--- a/sound/softsynth/mt32/synth.cpp
+++ b/sound/softsynth/mt32/synth.cpp
@@ -25,7 +25,7 @@
#include "mt32emu.h"
-#if defined(MACOSX) || defined(__solaris__)
+#if defined(MACOSX) || defined(SOLARIS)
// Older versions of Mac OS X didn't supply a powf function, so using it
// will cause a binary incompatibility when trying to run a binary built
// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
diff --git a/sound/softsynth/mt32/tables.cpp b/sound/softsynth/mt32/tables.cpp
index 20b7cf289a..5865ba2950 100644
--- a/sound/softsynth/mt32/tables.cpp
+++ b/sound/softsynth/mt32/tables.cpp
@@ -25,7 +25,7 @@
#include "mt32emu.h"
-#if defined(MACOSX) || defined(__solaris__)
+#if defined(MACOSX) || defined(SOLARIS)
// Older versions of Mac OS X didn't supply a powf function, so using it
// will cause a binary incompatibility when trying to run a binary built
// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp
index 64f67d2a13..da29b1b454 100644
--- a/sound/vorbis.cpp
+++ b/sound/vorbis.cpp
@@ -27,7 +27,7 @@
#ifdef USE_VORBIS
-#include "common/file.h"
+#include "common/stream.h"
#include "common/util.h"
#include "sound/audiostream.h"
diff --git a/sound/vorbis.h b/sound/vorbis.h
index 758bfd9487..012c33e310 100644
--- a/sound/vorbis.h
+++ b/sound/vorbis.h
@@ -31,7 +31,6 @@
#ifdef USE_VORBIS
namespace Common {
- class File;
class SeekableReadStream;
}
diff --git a/sound/wave.cpp b/sound/wave.cpp
index 249518aafc..72a3992401 100644
--- a/sound/wave.cpp
+++ b/sound/wave.cpp
@@ -34,7 +34,7 @@
namespace Audio {
bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) {
- const uint32 initialPos = stream.pos();
+ const int32 initialPos = stream.pos();
byte buf[4+1];
buf[4] = 0;
@@ -45,7 +45,7 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate,
return false;
}
- uint32 wavLength = stream.readUint32LE();
+ int32 wavLength = stream.readUint32LE();
stream.read(buf, 4);
if (memcmp(buf, "WAVE", 4) != 0) {
diff --git a/test/common/bufferedreadstream.h b/test/common/bufferedreadstream.h
index 7733949d9a..c580fd18de 100644
--- a/test/common/bufferedreadstream.h
+++ b/test/common/bufferedreadstream.h
@@ -9,12 +9,11 @@ class BufferedReadStreamTestSuite : public CxxTest::TestSuite {
Common::MemoryReadStream ms(contents, 10);
// Use a buffer size of 4 -- note that 10 % 4 != 0,
- // so we test what happens if the cache can't be completly
+ // so we test what happens if the cache can't be completely
// refilled.
Common::BufferedReadStream srs(&ms, 4);
- int i;
- byte b;
+ byte i, b;
for (i = 0; i < 10; ++i) {
TS_ASSERT( !srs.eos() );
@@ -22,6 +21,10 @@ class BufferedReadStreamTestSuite : public CxxTest::TestSuite {
TS_ASSERT_EQUALS( i, b );
}
- TS_ASSERT( srs.eos() );
+ TS_ASSERT( !srs.eos() );
+
+ b = srs.readByte();
+
+ TS_ASSERT ( srs.eos() );
}
};
diff --git a/test/common/bufferedseekablereadstream.h b/test/common/bufferedseekablereadstream.h
index 63941904cd..f039acd2a8 100644
--- a/test/common/bufferedseekablereadstream.h
+++ b/test/common/bufferedseekablereadstream.h
@@ -10,8 +10,7 @@ class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
Common::BufferedSeekableReadStream ssrs(&ms, 4);
- int i;
- byte b;
+ byte i, b;
for (i = 0; i < 10; ++i) {
TS_ASSERT( !ssrs.eos() );
@@ -21,6 +20,9 @@ class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
TS_ASSERT_EQUALS( i, b );
}
+ TS_ASSERT( !ssrs.eos() );
+
+ TS_ASSERT( 0 == ssrs.read(&b, 1) );
TS_ASSERT( ssrs.eos() );
}
@@ -31,34 +33,37 @@ class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
Common::BufferedSeekableReadStream ssrs(&ms, 4);
byte b;
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)0 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 0 );
ssrs.seek(1, SEEK_SET);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)1 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 1 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 1 );
ssrs.seek(5, SEEK_CUR);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)7 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 7 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 7 );
ssrs.seek(-3, SEEK_CUR);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)5 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 5 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 5 );
ssrs.seek(0, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)10 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 10 );
+ TS_ASSERT( !ssrs.eos() );
+ b = ssrs.readByte();
TS_ASSERT( ssrs.eos() );
ssrs.seek(3, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)7 );
+ TS_ASSERT( !ssrs.eos() );
+ TS_ASSERT_EQUALS( ssrs.pos(), 7 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 7 );
ssrs.seek(8, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)2 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 2 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 2 );
}
diff --git a/test/common/func.h b/test/common/func.h
new file mode 100644
index 0000000000..bf9b2ddff9
--- /dev/null
+++ b/test/common/func.h
@@ -0,0 +1,60 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/func.h"
+
+void myFunction1(int &dst, const int src) { dst = src; }
+void myFunction2(const int src, int &dst) { dst = src; }
+
+class FuncTestSuite : public CxxTest::TestSuite
+{
+ public:
+ void test_bind1st() {
+ int dst = 0;
+ Common::bind1st(Common::ptr_fun(myFunction1), dst)(1);
+ TS_ASSERT_EQUALS(dst, 1);
+ }
+
+ void test_bind2nd() {
+ int dst = 0;
+ Common::bind2nd(Common::ptr_fun(myFunction2), dst)(1);
+ TS_ASSERT_EQUALS(dst, 1);
+ }
+
+ struct Foo {
+ void fooAdd(int &foo) {
+ ++foo;
+ }
+
+ void fooSub(int &foo) const {
+ --foo;
+ }
+ };
+
+ void test_mem_fun_ref() {
+ Foo myFoos[4];
+ int counter = 0;
+
+ Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun_ref(&Foo::fooAdd), counter));
+ TS_ASSERT_EQUALS(counter, 4);
+
+ Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun_ref(&Foo::fooSub), counter));
+ TS_ASSERT_EQUALS(counter, 0);
+ }
+
+ void test_mem_fun() {
+ Foo *myFoos[4];
+ for (int i = 0; i < 4; ++i)
+ myFoos[i] = new Foo;
+
+ int counter = 0;
+
+ Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun(&Foo::fooAdd), counter));
+ TS_ASSERT_EQUALS(counter, 4);
+
+ Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun(&Foo::fooSub), counter));
+ TS_ASSERT_EQUALS(counter, 0);
+
+ for (int i = 0; i < 4; ++i)
+ delete myFoos[i];
+ }
+};
diff --git a/test/common/hashmap.h b/test/common/hashmap.h
index 5aa609bc00..acde1da028 100644
--- a/test/common/hashmap.h
+++ b/test/common/hashmap.h
@@ -1,12 +1,12 @@
#include <cxxtest/TestSuite.h>
#include "common/hashmap.h"
+#include "common/hash-str.h"
class HashMapTestSuite : public CxxTest::TestSuite
{
public:
- void test_empty_clear( void )
- {
+ void test_empty_clear(void) {
Common::HashMap<int, int> container;
TS_ASSERT( container.empty() );
container[0] = 17;
@@ -14,10 +14,17 @@ class HashMapTestSuite : public CxxTest::TestSuite
TS_ASSERT( !container.empty() );
container.clear();
TS_ASSERT( container.empty() );
+
+ Common::StringMap container2;
+ TS_ASSERT( container2.empty() );
+ container2["foo"] = "bar";
+ container2["quux"] = "blub";
+ TS_ASSERT( !container2.empty() );
+ container2.clear();
+ TS_ASSERT( container2.empty() );
}
- void test_contains( void )
- {
+ void test_contains(void) {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
@@ -25,25 +32,41 @@ class HashMapTestSuite : public CxxTest::TestSuite
TS_ASSERT( container.contains(1) );
TS_ASSERT( !container.contains(17) );
TS_ASSERT( !container.contains(-1) );
+
+ Common::StringMap container2;
+ container2["foo"] = "bar";
+ container2["quux"] = "blub";
+ TS_ASSERT( container2.contains("foo") );
+ TS_ASSERT( container2.contains("quux") );
+ TS_ASSERT( !container2.contains("bar") );
+ TS_ASSERT( !container2.contains("asdf") );
}
- void test_add_remove( void )
- {
+ void test_add_remove(void) {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
+ container[2] = 45;
+ container[3] = 12;
+ container[4] = 96;
TS_ASSERT( container.contains(1) );
container.erase(1);
TS_ASSERT( !container.contains(1) );
container[1] = 42;
TS_ASSERT( container.contains(1) );
container.erase(0);
+ TS_ASSERT( !container.empty() );
container.erase(1);
+ TS_ASSERT( !container.empty() );
+ container.erase(2);
+ TS_ASSERT( !container.empty() );
+ container.erase(3);
+ TS_ASSERT( !container.empty() );
+ container.erase(4);
TS_ASSERT( container.empty() );
}
- void test_lookup( void )
- {
+ void test_lookup(void) {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = -1;
@@ -58,8 +81,7 @@ class HashMapTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS( container[4], 96 );
}
- void test_iterator_begin_end( void )
- {
+ void test_iterator_begin_end(void) {
Common::HashMap<int, int> container;
// The container is initially empty ...
@@ -74,12 +96,11 @@ class HashMapTestSuite : public CxxTest::TestSuite
TS_ASSERT( container.begin() == container.end() );
}
- void test_hash_map_copy( void )
- {
- Common::HashMap<int, int> map1, map2;
+ void test_hash_map_copy(void) {
+ Common::HashMap<int, int> map1, container2;
map1[323] = 32;
- map2 = map1;
- TS_ASSERT_EQUALS(map2[323], 32);
+ container2 = map1;
+ TS_ASSERT_EQUALS(container2[323], 32);
}
// TODO: Add test cases for iterators, find, ...
diff --git a/test/common/queue.h b/test/common/queue.h
new file mode 100644
index 0000000000..7eedec9a5d
--- /dev/null
+++ b/test/common/queue.h
@@ -0,0 +1,80 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/queue.h"
+
+class QueueTestSuite : public CxxTest::TestSuite {
+public:
+ void test_empty_clear() {
+ Common::Queue<int> queue;
+ TS_ASSERT(queue.empty());
+
+ queue.push(1);
+ queue.push(2);
+ TS_ASSERT(!queue.empty());
+
+ queue.clear();
+
+ TS_ASSERT(queue.empty());
+ }
+
+ void test_size() {
+ Common::Queue<int> queue;
+ TS_ASSERT_EQUALS(queue.size(), 0);
+
+ queue.push(5);
+ TS_ASSERT_EQUALS(queue.size(), 1);
+
+ queue.push(9);
+ queue.push(0);
+ TS_ASSERT_EQUALS(queue.size(), 3);
+
+ queue.pop();
+ TS_ASSERT_EQUALS(queue.size(), 2);
+ }
+
+ void test_front_back_pop() {
+ Common::Queue<int> queue;
+
+ queue.push( 42);
+ queue.push(-23);
+
+ TS_ASSERT_EQUALS(queue.front(), 42);
+ TS_ASSERT_EQUALS(queue.back(), -23);
+
+ queue.front() = -23;
+ queue.back() = 42;
+ TS_ASSERT_EQUALS(queue.front(), -23);
+ TS_ASSERT_EQUALS(queue.back(), 42);
+
+ queue.pop();
+ TS_ASSERT_EQUALS(queue.front(), 42);
+ }
+
+ void test_assign() {
+ Common::Queue<int> q1, q2;
+
+ for (int i = 0; i < 5; ++i) {
+ q1.push(i);
+ q2.push(4-i);
+ }
+
+ Common::Queue<int> q3(q1);
+
+ for (int i = 0; i < 5; ++i) {
+ TS_ASSERT_EQUALS(q3.front(), i);
+ q3.pop();
+ }
+
+ TS_ASSERT(q3.empty());
+
+ q3 = q2;
+
+ for (int i = 4; i >= 0; --i) {
+ TS_ASSERT_EQUALS(q3.front(), i);
+ q3.pop();
+ }
+
+ TS_ASSERT(q3.empty());
+ }
+};
+
diff --git a/test/common/seekablesubreadstream.h b/test/common/seekablesubreadstream.h
index 4e517093a5..68febc7fd6 100644
--- a/test/common/seekablesubreadstream.h
+++ b/test/common/seekablesubreadstream.h
@@ -17,12 +17,14 @@ class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite {
for (i = start; i < end; ++i) {
TS_ASSERT( !ssrs.eos() );
- TS_ASSERT_EQUALS( uint32(i - start), ssrs.pos() );
+ TS_ASSERT_EQUALS( i - start, ssrs.pos() );
ssrs.read(&b, 1);
TS_ASSERT_EQUALS( i, b );
}
+ TS_ASSERT( !ssrs.eos() );
+ TS_ASSERT( 0 == ssrs.read(&b, 1) );
TS_ASSERT( ssrs.eos() );
}
@@ -33,34 +35,37 @@ class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite {
Common::SeekableSubReadStream ssrs(&ms, 1, 9);
byte b;
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)0 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 0 );
ssrs.seek(1, SEEK_SET);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)1 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 1 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 2 );
ssrs.seek(5, SEEK_CUR);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)7 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 7 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 8 );
ssrs.seek(-3, SEEK_CUR);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)5 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 5 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 6 );
ssrs.seek(0, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)8 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 8 );
+ TS_ASSERT( !ssrs.eos() );
+ b = ssrs.readByte();
TS_ASSERT( ssrs.eos() );
ssrs.seek(3, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)5 );
+ TS_ASSERT( !ssrs.eos() );
+ TS_ASSERT_EQUALS( ssrs.pos(), 5 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 6 );
ssrs.seek(8, SEEK_END);
- TS_ASSERT_EQUALS( ssrs.pos(), (uint32)0 );
+ TS_ASSERT_EQUALS( ssrs.pos(), 0 );
b = ssrs.readByte();
TS_ASSERT_EQUALS( b, 1 );
}
diff --git a/test/common/str.h b/test/common/str.h
index 72d4df6f61..c352bd1887 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -157,4 +157,81 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(str, "TEST IT, NOW! 42");
TS_ASSERT_EQUALS(str2, "Test it, NOW! 42");
}
+
+ void test_deleteChar( void )
+ {
+ Common::String str("01234567890123456789012345678901");
+ str.deleteChar(10);
+ TS_ASSERT_EQUALS( str, "0123456789123456789012345678901" );
+ str.deleteChar(10);
+ TS_ASSERT_EQUALS( str, "012345678923456789012345678901" );
+ }
+
+ void test_sharing( void )
+ {
+ Common::String str("01234567890123456789012345678901");
+ Common::String str2(str);
+ TS_ASSERT_EQUALS( str2, "01234567890123456789012345678901" );
+ str.deleteLastChar();
+ TS_ASSERT_EQUALS( str, "0123456789012345678901234567890" );
+ TS_ASSERT_EQUALS( str2, "01234567890123456789012345678901" );
+ }
+
+ void test_lastPathComponent(void) {
+ TS_ASSERT(Common::lastPathComponent("/", '/') == "");
+ TS_ASSERT(Common::lastPathComponent("/foo/bar", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("/foo//bar/", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("/foo/./bar", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("/foo//./bar//", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("/foo//.bar//", '/') == ".bar");
+
+ TS_ASSERT(Common::lastPathComponent("", '/') == "");
+ TS_ASSERT(Common::lastPathComponent("foo/bar", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("foo//bar/", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("foo/./bar", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("foo//./bar//", '/') == "bar");
+ TS_ASSERT(Common::lastPathComponent("foo//.bar//", '/') == ".bar");
+ }
+
+ void test_normalizePath(void) {
+ TS_ASSERT(Common::normalizePath("/", '/') == "/");
+ TS_ASSERT(Common::normalizePath("/foo/bar", '/') == "/foo/bar");
+ TS_ASSERT(Common::normalizePath("/foo//bar/", '/') == "/foo/bar");
+ TS_ASSERT(Common::normalizePath("/foo/./bar", '/') == "/foo/bar");
+ TS_ASSERT(Common::normalizePath("/foo//./bar//", '/') == "/foo/bar");
+ TS_ASSERT(Common::normalizePath("/foo//.bar//", '/') == "/foo/.bar");
+
+ TS_ASSERT(Common::normalizePath("", '/') == "");
+ TS_ASSERT(Common::normalizePath("foo/bar", '/') == "foo/bar");
+ TS_ASSERT(Common::normalizePath("foo//bar/", '/') == "foo/bar");
+ TS_ASSERT(Common::normalizePath("foo/./bar", '/') == "foo/bar");
+ TS_ASSERT(Common::normalizePath("foo//./bar//", '/') == "foo/bar");
+ TS_ASSERT(Common::normalizePath("foo//.bar//", '/') == "foo/.bar");
+ }
+
+ void test_matchString(void) {
+ TS_ASSERT( Common::matchString("", "*"));
+ TS_ASSERT( Common::matchString("a", "*"));
+ TS_ASSERT( Common::matchString("monkey.s01", "*"));
+
+ TS_ASSERT(!Common::matchString("", "?"));
+ TS_ASSERT( Common::matchString("a", "?"));
+ TS_ASSERT(!Common::matchString("monkey.s01", "?"));
+
+ TS_ASSERT( Common::matchString("monkey.s01", "monkey.s??"));
+ TS_ASSERT( Common::matchString("monkey.s99", "monkey.s??"));
+ TS_ASSERT(!Common::matchString("monkey.s101", "monkey.s??"));
+
+ TS_ASSERT( Common::matchString("monkey.s01", "monkey.s?1"));
+ TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s?1"));
+ TS_ASSERT(!Common::matchString("monkey.s101", "monkey.s?1"));
+
+ TS_ASSERT( Common::matchString("monkey.s01", "monkey.s*"));
+ TS_ASSERT( Common::matchString("monkey.s99", "monkey.s*"));
+ TS_ASSERT( Common::matchString("monkey.s101", "monkey.s*"));
+
+ TS_ASSERT( Common::matchString("monkey.s01", "monkey.s*1"));
+ TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s*1"));
+ TS_ASSERT( Common::matchString("monkey.s101", "monkey.s*1"));
+ }
};
diff --git a/test/common/stream.h b/test/common/stream.h
new file mode 100644
index 0000000000..a605d34a2c
--- /dev/null
+++ b/test/common/stream.h
@@ -0,0 +1,46 @@
+#include <cxxtest/TestSuite.h>
+
+#include "common/stream.h"
+
+class ReadLineStreamTestSuite : public CxxTest::TestSuite {
+ public:
+ void test_readline(void) {
+ byte contents[] = { 'a', 'b', '\n', '\n', 'c', '\n' };
+ Common::MemoryReadStream ms(contents, sizeof(contents));
+
+ char buffer[100];
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "ab\n"));
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "\n"));
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "c\n"));
+
+ TS_ASSERT(!ms.eos());
+
+ TS_ASSERT(0 == ms.readLine_NEW(buffer, sizeof(buffer)));
+
+ TS_ASSERT(ms.eos());
+ }
+
+ void test_readline2(void) {
+ byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
+ Common::MemoryReadStream ms(contents, sizeof(contents));
+
+ char buffer[100];
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "ab\n"));
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "\n"));
+
+ TS_ASSERT(0 != ms.readLine_NEW(buffer, sizeof(buffer)));
+ TS_ASSERT(0 == strcmp(buffer, "c"));
+
+ TS_ASSERT(ms.eos());
+ }
+};
diff --git a/test/common/subreadstream.h b/test/common/subreadstream.h
index 4e14448c06..2ac453576a 100644
--- a/test/common/subreadstream.h
+++ b/test/common/subreadstream.h
@@ -21,6 +21,8 @@ class SubReadStreamTestSuite : public CxxTest::TestSuite {
TS_ASSERT_EQUALS( i, b );
}
+ TS_ASSERT( !srs.eos() );
+ b = srs.readByte();
TS_ASSERT( srs.eos() );
}
};
diff --git a/tools/create_drascula/create_drascula.cpp b/tools/create_drascula/create_drascula.cpp
index 2676376e42..e150fa7518 100644
--- a/tools/create_drascula/create_drascula.cpp
+++ b/tools/create_drascula/create_drascula.cpp
@@ -38,7 +38,7 @@
#include "create_drascula.h"
#include "staticdata.h"
-#define DRASCULA_DAT_VER 2 // 1 byte
+#define DRASCULA_DAT_VER 4 // 1 byte
static void writeByte(FILE *fp, uint8 b) {
fwrite(&b, 1, 1, fp);
@@ -172,6 +172,16 @@ int main(int argc, char *argv[]) {
writeSint16BE(outFile, roomActions[i].speechID);
}
+ // Write talk sequences
+ writeUint16BE(outFile, ARRAYSIZE(talkSequences));
+
+ for (i = 0; i < ARRAYSIZE(talkSequences); i++) {
+ writeSint16BE(outFile, talkSequences[i].chapter);
+ writeSint16BE(outFile, talkSequences[i].sequence);
+ writeSint16BE(outFile, talkSequences[i].commandType);
+ writeSint16BE(outFile, talkSequences[i].action);
+ }
+
// langs
writeUint16BE(outFile, NUM_LANGS);
diff --git a/tools/create_drascula/create_drascula.h b/tools/create_drascula/create_drascula.h
index ed81651e86..51287c43d2 100644
--- a/tools/create_drascula/create_drascula.h
+++ b/tools/create_drascula/create_drascula.h
@@ -93,5 +93,39 @@ struct RoomUpdate {
int type; // 0 - background, 1 - rect
};
+enum TalkSequenceCommands {
+ kPause = 0,
+ kSetFlag = 1,
+ kClearFlag = 2,
+ kPickObject = 3,
+ kAddObject = 4,
+ kBreakOut = 5,
+ kConverse = 6,
+ kPlaceVB = 7,
+ kUpdateRoom = 8,
+ kUpdateScreen = 9,
+ kTrackProtagonist = 10,
+ kPlaySound = 11,
+ kFinishSound = 12,
+ kTalkerGeneral = 13,
+ kTalkerDrunk = 14,
+ kTalkerPianist = 15,
+ kTalkerBJ = 16,
+ kTalkerVBNormal = 17,
+ kTalkerVBDoor = 18,
+ kTalkerIgorSeated = 19,
+ kTalkerWerewolf = 20,
+ kTalkerMus = 21,
+ kTalkerDrascula = 22,
+ kTalkerBartender0 = 23,
+ kTalkerBartender1 = 24
+};
+
+struct TalkSequenceCommand {
+ int chapter;
+ int sequence;
+ int commandType;
+ int action;
+};
#endif /* CREATE_DRASCULA_H */
diff --git a/tools/create_drascula/staticdata.h b/tools/create_drascula/staticdata.h
index 4778c530e4..f5fd018172 100644
--- a/tools/create_drascula/staticdata.h
+++ b/tools/create_drascula/staticdata.h
@@ -636,6 +636,254 @@ RoomTalkAction roomActions[] = {
};
+TalkSequenceCommand talkSequences[] = {
+ // Chapter, sequence, command type, action
+ { 1, 2, kTalkerBJ, 2 },
+ { 1, 2, kTalkerGeneral, 215 },
+ { 1, 2, kTalkerBJ, 3 },
+ { 1, 2, kTalkerGeneral, 216 },
+ { 1, 2, kTalkerBJ, 4 },
+ { 1, 2, kTalkerBJ, 5 },
+ { 1, 2, kTalkerBJ, 6 },
+ { 1, 2, kTalkerGeneral, 217 },
+ { 1, 2, kTalkerBJ, 7 },
+ { 1, 2, kTalkerGeneral, 218 },
+ { 1, 2, kTalkerBJ, 8 },
+ { 1, 2, kTalkerGeneral, 219 },
+ { 1, 2, kTalkerBJ, 9 },
+ { 1, 2, kTalkerGeneral, 220 },
+ { 1, 2, kTalkerGeneral, 221 },
+ { 1, 2, kTalkerBJ, 10 },
+ { 1, 2, kTalkerGeneral, 222 },
+ //
+ { 1, 3, kTalkerGeneral, 192 },
+ { 1, 3, kTalkerBartender0, 1 },
+ { 1, 3, kTalkerGeneral, 193 },
+ { 1, 3, kTalkerBartender0, 2 },
+ { 1, 3, kTalkerGeneral, 194 },
+ { 1, 3, kTalkerBartender0, 3 },
+ { 1, 3, kTalkerGeneral, 195 },
+ { 1, 3, kTalkerBartender0, 4 },
+ { 1, 3, kTalkerGeneral, 196 },
+ { 1, 3, kTalkerBartender0, 5 },
+ { 1, 3, kTalkerBartender0, 6 },
+ { 1, 3, kTalkerGeneral, 197 },
+ { 1, 3, kTalkerBartender0, 7 },
+ { 1, 3, kTalkerGeneral, 198 },
+ { 1, 3, kTalkerBartender0, 8 },
+ { 1, 3, kTalkerGeneral, 199 },
+ { 1, 3, kTalkerBartender0, 9 },
+ { 1, 3, kTalkerGeneral, 200 },
+ { 1, 3, kTalkerGeneral, 201 },
+ { 1, 3, kTalkerGeneral, 202 },
+ { 1, 3, kSetFlag, 0 },
+ //
+ { 1, 10, kTalkerDrunk, 1 },
+ { 1, 11, kTalkerDrunk, 2 },
+ { 1, 12, kTalkerDrunk, 3 },
+ //
+ { 2, 8, kTalkerPianist, 6 },
+ { 2, 8, kTalkerGeneral, 358 },
+ { 2, 8, kTalkerPianist, 7 },
+ { 2, 8, kTalkerPianist, 8 },
+ //
+ { 2, 9, kTalkerPianist, 9 },
+ { 2, 9, kTalkerPianist, 10 },
+ { 2, 9, kTalkerPianist, 11 },
+ //
+ { 2, 10, kTalkerPianist, 12 },
+ { 2, 10, kTalkerGeneral, 361 },
+ { 2, 10, kPause, 40 },
+ { 2, 10, kTalkerPianist, 13 },
+ { 2, 10, kTalkerGeneral, 362 },
+ { 2, 10, kTalkerPianist, 14 },
+ { 2, 10, kTalkerGeneral, 363 },
+ { 2, 10, kTalkerPianist, 15 },
+ { 2, 10, kTalkerGeneral, 364 },
+ { 2, 10, kTalkerPianist, 16 },
+ { 2, 10, kTalkerGeneral, 365 },
+ //
+ { 2, 11, kTalkerGeneral, 352 },
+ { 2, 11, kTalkerBartender0, 1 },
+ { 2, 11, kTalkerGeneral, 353 },
+ { 2, 11, kTalkerBartender0, 17 },
+ { 2, 11, kTalkerGeneral, 354 },
+ { 2, 11, kTalkerBartender0, 18 },
+ { 2, 11, kTalkerGeneral, 355 },
+ { 2, 11, kPause, 40 },
+ { 2, 11, kTalkerBartender0, 82 },
+ //
+ { 2, 13, kTalkerGeneral, 103 },
+ { 2, 13, kTalkerDrunk, 4 },
+ { 2, 13, kSetFlag, 12 },
+ { 2, 13, kTalkerGeneral, 367 },
+ { 2, 13, kTalkerDrunk, 5 },
+ { 2, 13, kSetFlag, 12 },
+ { 2, 13, kTalkerGeneral, 368 },
+ { 2, 13, kTalkerDrunk, 6 },
+ { 2, 13, kTalkerDrunk, 7 },
+ { 2, 13, kSetFlag, 41 },
+ { 2, 13, kConverse, 2 },
+ //
+ { 2, 15, kTalkerDrunk, 8 },
+ { 2, 15, kPause, 7 },
+ { 2, 15, kTalkerDrunk, 9 },
+ { 2, 15, kTalkerDrunk, 10 },
+ { 2, 15, kTalkerDrunk, 11 },
+ //
+ { 2, 17, kTalkerDrunk, 13 },
+ { 2, 17, kTalkerDrunk, 14 },
+ { 2, 17, kSetFlag, 40 },
+ { 2, 19, kTalkerVBDoor, 5 },
+ { 2, 21, kTalkerVBDoor, 6 },
+ //
+ { 2, 22, kTalkerGeneral, 374 },
+ { 2, 22, kTrackProtagonist, 2 },
+ { 2, 22, kUpdateRoom, -1 },
+ { 2, 22, kUpdateScreen, -1 },
+ { 2, 22, kPlaySound, 13 },
+ { 2, 22, kFinishSound, -1 },
+ { 2, 22, kTrackProtagonist, 1 },
+ { 2, 22, kTalkerVBDoor, 1 },
+ { 2, 22, kTalkerGeneral, 375 },
+ { 2, 22, kTalkerVBDoor, 2 },
+ { 2, 22, kTalkerGeneral, 376 },
+ { 2, 22, kTalkerVBDoor, 3 },
+ { 2, 22, kSetFlag, 18 },
+ //
+ { 2, 28, kTalkerVBNormal, 27 },
+ { 2, 28, kTalkerVBNormal, 28 },
+ { 2, 28, kTalkerVBNormal, 29 },
+ { 2, 28, kTalkerVBNormal, 30 },
+ //
+ { 2, 29, kTalkerVBNormal, 32 },
+ { 2, 29, kTalkerGeneral, 398 },
+ { 2, 29, kTalkerVBNormal, 33 },
+ { 2, 29, kTalkerGeneral, 399 },
+ { 2, 29, kTalkerVBNormal, 34 },
+ { 2, 29, kTalkerVBNormal, 35 },
+ { 2, 29, kTalkerGeneral, 400 },
+ { 2, 29, kTalkerVBNormal, 36 },
+ { 2, 29, kTalkerVBNormal, 37 },
+ { 2, 29, kTalkerGeneral, 386 },
+ { 2, 29, kTalkerVBNormal, 38 },
+ { 2, 29, kTalkerVBNormal, 39 },
+ { 2, 29, kTalkerGeneral, 401 },
+ { 2, 29, kTalkerVBNormal, 40 },
+ { 2, 29, kTalkerVBNormal, 41 },
+ { 2, 29, kSetFlag, 33 },
+ //
+ { 2, 30, kTalkerVBNormal, 31 },
+ { 2, 30, kTalkerGeneral, 396 },
+ //
+ { 2, 31, kTrackProtagonist, 2 },
+ { 2, 31, kUpdateRoom, -1 },
+ { 2, 31, kUpdateScreen, -1 },
+ { 2, 31, kPause, 78 },
+ { 2, 31, kTrackProtagonist, 0 },
+ { 2, 31, kUpdateRoom, -1 },
+ { 2, 31, kUpdateScreen, -1 },
+ { 2, 31, kPause, 22 },
+ { 2, 31, kTalkerGeneral, 406 },
+ { 2, 31, kPlaceVB, 98 },
+ { 2, 31, kTalkerVBNormal, 45 },
+ { 2, 31, kTalkerVBNormal, 46 },
+ { 2, 31, kTalkerVBNormal, 47 },
+ { 2, 31, kTalkerGeneral, 407 },
+ { 2, 31, kTalkerVBNormal, 48 },
+ { 2, 31, kTalkerVBNormal, 49 },
+ { 2, 31, kTalkerGeneral, 408 },
+ { 2, 31, kTalkerVBNormal, 50 },
+ { 2, 31, kTalkerVBNormal, 51 },
+ { 2, 31, kTalkerGeneral, 409 },
+ { 2, 31, kTalkerVBNormal, 52 },
+ { 2, 31, kTalkerVBNormal, 53 },
+ { 2, 31, kPause, 12 },
+ { 2, 31, kTalkerVBNormal, 54 },
+ { 2, 31, kTalkerVBNormal, 55 },
+ { 2, 31, kTalkerGeneral, 410 },
+ { 2, 31, kTalkerVBNormal, 56 },
+ { 2, 31, kBreakOut, 1 },
+ { 2, 31, kClearFlag, 38 },
+ { 2, 31, kSetFlag, 36 },
+ //
+ { 4, 2, kTalkerIgorSeated, 16 },
+ { 4, 2, kTalkerGeneral, 278 },
+ { 4, 2, kTalkerIgorSeated, 17 },
+ { 4, 2, kTalkerGeneral, 279 },
+ { 4, 2, kTalkerIgorSeated, 18 },
+ { 4, 3, kTalkerIgorSeated, 19 },
+ { 4, 3, kTalkerIgorSeated, 20 },
+ { 4, 3, kTalkerGeneral, 281 },
+ { 4, 4, kTalkerGeneral, 287 },
+ { 4, 4, kTalkerIgorSeated, 21 },
+ { 4, 4, kTalkerGeneral, 284 },
+ { 4, 4, kTalkerIgorSeated, 22 },
+ { 4, 4, kTalkerGeneral, 285 },
+ { 4, 4, kTalkerIgorSeated, 23 },
+ //
+ { 5, 2, kTalkerBJ, 22 },
+ { 5, 3, kTalkerBJ, 23 },
+ { 5, 3, kPickObject, 10 },
+ { 5, 3, kBreakOut, 1 },
+ //
+ { 5, 4, kSetFlag, 7 },
+ { 5, 4, kUpdateRoom, -1 },
+ { 5, 4, kUpdateScreen, -1 },
+ { 5, 4, kTalkerGeneral, 228 },
+ { 5, 4, kTalkerWerewolf, 1 },
+ { 5, 4, kTalkerWerewolf, 2 },
+ { 5, 4, kPause, 23 },
+ { 5, 4, kTalkerGeneral, 229 },
+ { 5, 4, kTalkerWerewolf, 3 },
+ { 5, 4, kTalkerWerewolf, 4 },
+ { 5, 4, kTalkerGeneral, 230 },
+ { 5, 4, kTalkerWerewolf, 5 },
+ { 5, 4, kTalkerGeneral, 231 },
+ { 5, 4, kTalkerWerewolf, 6 },
+ { 5, 4, kTalkerWerewolf, 7 },
+ { 5, 4, kPause, 33 },
+ { 5, 4, kTalkerGeneral, 232 },
+ { 5, 4, kTalkerWerewolf, 8 },
+ //
+ { 5, 6, kTalkerWerewolf, 9 },
+ { 5, 6, kTalkerGeneral, 234 },
+ { 5, 7, kTalkerWerewolf, 10 },
+ { 5, 7, kTalkerGeneral, 236 },
+ { 5, 7, kTalkerWerewolf, 11 },
+ { 5, 7, kTalkerWerewolf, 12 },
+ { 5, 7, kTalkerWerewolf, 13 },
+ { 5, 7, kPause, 34 },
+ { 5, 7, kTalkerWerewolf, 14 },
+ { 5, 8, kTalkerWerewolf, 15 },
+ { 5, 8, kTalkerGeneral, 238 },
+ { 5, 8, kTalkerWerewolf, 16 },
+ { 5, 15, kTalkerMus, 4 },
+ { 5, 15, kTalkerMus, 5 },
+ { 5, 15, kTalkerMus, 6 },
+ { 5, 15, kTalkerGeneral, 291 },
+ { 5, 15, kTalkerMus, 7 },
+ { 5, 16, kTalkerMus, 8 },
+ { 5, 17, kTalkerMus, 9 },
+ //
+ { 6, 2, kTalkerDrascula, 24 },
+ { 6, 3, kTalkerDrascula, 24 },
+ { 6, 4, kTalkerDrascula, 25 },
+ { 6, 11, kTalkerBartender1, 10 },
+ { 6, 11, kTalkerGeneral, 268 },
+ { 6, 11, kTalkerBartender1, 11 },
+ { 6, 12, kTalkerBartender1, 12 },
+ { 6, 12, kTalkerGeneral, 270 },
+ { 6, 12, kTalkerBartender1, 13 },
+ { 6, 12, kTalkerBartender1, 14 },
+ { 6, 13, kTalkerBartender1, 15 },
+ { 6, 14, kTalkerBartender1, 24 },
+ { 6, 14, kAddObject, 21 },
+ { 6, 14, kSetFlag, 10 },
+ { 6, 14, kBreakOut, 1 },
+ { 6, 15, kTalkerBartender1, 16 }
+};
+
const char *_text[NUM_LANGS][NUM_TEXT] = {
{
// 0
@@ -3056,84 +3304,84 @@ const char *_text[NUM_LANGS][NUM_TEXT] = {
{
// 0
"",
- "\220 la seconda porta pi\243 grande che ho vista nella mia vita",
- "Forse.., no",
- "\202 chiusa con tabelle. La chiesa deve essere abbandonata da tanti anni fa.",
- "Ma se non la ho aperta",
+ "\324 LA SECONDA PORTA PI\353 GRANDE CHE IO ABBIA MAI VISTO",
+ "BEH, FORSE NO",
+ "\324 SIGILLATA CON TAVOLE. LA CHIESA DEV'ESSERE STATA ABBANDONATA PARECCHI ANNI FA.",
+ "NON L'HO APERTA",
// 5
- "Che faccio? La tolgo?",
- "Ciao porta. Vado a farti una cornice",
- "Troppo per me",
- "una finestra chiusa con tabelle",
- "Non ce la faccio",
+ "CHE FACCIO? LA TOLGO?",
+ "CIAO PORTA. STO PER TRASFORMARTI IN UNO STIPITE.",
+ "\324 TROPPO PER ME.",
+ "UNA FINESTRA SIGILLATA CON TAVOLE.",
+ "NON POSSO.",
// 10
- "Eccolo",
- "E per che?",
- "Ciao finestra. Hai qualcosa da fare stasera?",
- "No senza il permesso del Ministero dei Lavori Pubblici",
- "-eh! quella finestra ha soltanto una tabella..",
+ "GI\267 FATTO.",
+ "E PERCH\220?",
+ "CIAO FINESTRA. HAI QUALCOSA DA FARE STANOTTE?",
+ "NON SENZA IL PERMESSO DEL MINISTERO DELLE OPERE PUBBLICHE",
+ "SE SOLO QUESTA FINESTRA NON FOSSE SIGILLATA...",
// 15
- "-Eooooo! -Finestra!",
- "Tu, ciao",
- "",
- "Non ce la faccio",
- "Va bene dov'\202 ",
+ "YOO-HOO! FINESTRA!",
+ "SALVE.",
+ "COME QUELLA DELLA MICROCHOF.",
+ "NON RIESCO AD ARRIVARCI.",
+ "STA BENE DOV'\324.",
// 20
"",
- "\220 una tomba in forma di croce",
- "Non grazie",
- "Ciao morto. Vuoi delle patatine a forma di vermi?",
- "Si. Come in Poltergueist.",
+ "\324 UNA LAPIDE A FORMA DI CROCE",
+ "NO GRAZIE.",
+ "CIAO, MORTO. NON TI SCOMODARE AD ALZARTI!",
+ "S\326, CERTO. COME IN POLTERGEIST.",
// 25
"",
"",
- "Torno in quindici minuti",
- "Vietato affigere manifesti",
- "",
+ "TORNO TRA QUINDICI MINUTI.",
+ "VIETATO AFFIGGERE MANIFESTI.",
+ "\324 LA TOMBA DELLO ZIO EVARISTO.",
// 30
- "\220 chiuso con la chiave",
- "Ne ho gi\240 uno.",
- "",
- "Non risponde.",
- "No, \202 ben parcheggiato.",
+ "\324 CHIUSA A CHIAVE",
+ "NE HO GI\267 UNO.",
+ "YOO HOO, ZIO EVARISTO!",
+ "NON RISPONDE.",
+ "NO, \324 FISSATO PER BENE.",
// 35
- "\220 una porta.",
- "Un casseto del tavolino.",
- "Un sospettoso armadio.",
- "Ciao armadio. Come va?.",
+ "\324 UNA PORTA.",
+ "UN CASSETTO DEL TAVOLO.",
+ "UN ARMADIO SOSPETTO.",
+ "CIAO ARMADIO. COME VA?",
"",
// 40
"",
- "\220 un candelabro molto vecchio.",
- "Deve essere qu\241 da che Mazinguer-Z era una vite.",
- "No.\220 una reliquia.",
- "\220 una bella pala.",
+ "\324 UN CANDELABRO MOLTO ANTICO.",
+ "DEV'ESSERE QUI DA QUANDO MAZINGA Z ERA UNA VITE.",
+ "NO, \324 UNA RELIQUIA.",
+ "\324 UNA GRAZIOSA PALA D'ALTARE.",
// 45
"",
- "Hi, hi, hi",
+ "HI, HI, HI.",
"",
- "No.",
+ "NO.",
"",
// 50
- "Ha,ha,ha . - che buono!",
+ "HA, HA, HA. FANTASTICO!",
"",
"",
"",
- "Non vedo niente di speciale.",
+ "NON VEDO NIENTE DI SPECIALE.",
// 55
- "Ferdinan, la pianta.",
- "\220 una degli spunzoni della cancellata.",
- "-Eh! Qu\241 sotto c'\202 una scatola di cerini",
- "-Guarda! un pacco di fazzoletti. -E c'\202 ne uno senza utilizzare!.",
- "Non c'\202 niente di pi\243 nel secchio.",
+ "\324 FERNAN, LA PIANTA.",
+ "\324 UNO DEI PALETTI DELLA STACCIONATA.",
+ "HEY! C'\324 UN PACCHETTO DI FIAMMIFERI QUI SOTTO.",
+ "MA GUARDA! UN PACCHETTO DI FAZZOLETTI. CE N'\324 ANCORA UNO NON USATO!",
+ "NON C'\324 ALTRO NEL CESTINO.",
// 60
- "\220 un cieco che non vede",
+ "\324 UN CIECO CHE NON VEDE.",
"",
"",
"",
"",
// 65
- "\220 una abbondante quantit\240 di soldi",
+ "\324 UNA BELLA SOMMA DI DENARO.",
"",
"",
"",
@@ -3175,487 +3423,487 @@ const char *_text[NUM_LANGS][NUM_TEXT] = {
"",
"",
// 100
- "NON HA NULLA DI SPECIALE",
- "NON \324 MICA SPECIALE",
- "TU! CHE C'\324 ?",
+ "NON HA NULLA DI SPECIALE.",
+ "NON \324 NIENTE DI INSOLITO.",
+ "COME TE LA PASSI?",
"CIAO",
- "NIENTE NUOVO?",
+ "NIENTE DI NUOVO?",
// 105
- "-COME VA LA FAMIGLIA?",
- "- MA CHE STAI A DIRE?",
- "-MA COME VADO A PRENDERE QUELLA COSA!",
- "\324 VIETATO DALLA MIA RELIGIONE",
- "MEGLIO DI NO",
+ "COME VA LA FAMIGLIA?",
+ "DICI SUL SERIO?",
+ "MA COME FACCIO A PRENDERLO?",
+ "LA MIA RELIGIONE ME LO PROIBISCE.",
+ "MEGLIO DI NO.",
// 110
- "-COME NO!",
- "NEANCHE PARLARNE",
+ "SICURO!",
+ "NEANCHE A PARLARNE.",
"IMPOSSIBILE",
"QUESTO NON SI APRE",
- "IO SOLO NON CE LA FACCIO",
+ "NON CE LA FACCIO DA SOLO",
// 115
- "SE VORREI POTREI, MA MI FA PIGRIZIA",
- "NON TROVO UNA BUONA RAGIONE",
- "\324 UN CERVELLO ABBASTANZA CARINO",
- "ALLORA, CERVELLO, CHE NE PENSI DI FARE STASERA?",
- "NO, DEVE CONSERVARSI IN UN POSTO CHIUSO ALLA AZIONE MUTANTE DELLA ATMOSFERA",
+ "POTREI FARLO, MA MI SENTO UN PO' PIGRO.",
+ "NON NE VEDO IL MOTIVO.",
+ "\324 UN CERVELLO PIUTTOSTO CARINO.",
+ "E ALLORA, CERVELLO, CHE PENSI DI FARE STANOTTE?",
+ "NO, DEVE ESSERE CONSERVATO IN UN POSTO LONTANO DALL'AZIONE MUTAGENA DELL'ATMOSFERA",
// 120
- "\324 COS\336 DURO, COME IL MIO CAPO",
- "UNA TALEA MOLTO AFFILATA",
- "FEDELE TALEA AFFILATAAA, NOBILE ROVERE TRANSILVANOOO",
- "-INSOMMA, DEVO TAGLIARMI LE UNGHIE!",
- "-LA, DENTRO, C'\324 B.J,E MAMMA MIA, CHE FIGA!",
+ "\324 RIGIDO, COME IL MIO CAPO",
+ "UN PICCHETTO MOLTO AFFILATO.",
+ "FEDELE PICCHETTO APPUNTITOOO, NOBILE ROVERE TRANSILVANOOO",
+ "ACCIDENTI, MI DEVO TAGLIARE LE UNGHIE!",
+ "L\326 DENTRO C'\324 B.J., DOVREI VEDERE COME STA LA RAGAZZA!",
// 125
- "\324 CHIUSA SOTTO LUCCHETTO E CATENACCIO",
- "\"LUCCHETTO E CATENACCIO S.A\"",
- "\324 IL TIPICO SCHELETRO CHE C'\324 IN TUTTE LE CARCERE DI TUTTI I VIDEO-GIOCHI",
- "SI UTILIZA PER DARE ELETRICIT\267 AGLI APARATTI COLLEGATI A LUI",
- "\324 TOTALMEN11TE ARTIGIANO, PERCHE I GIAPONESSI LI FANNO TASCABILI",
+ "\324 CHIUSA CON LUCCHETTO E CATENACCIO",
+ "\"LUCCHETTO E CATENACCIO S.P.A.\"",
+ "\324 IL TIPICO SCHELETRO CHE C'\324 IN TUTTE LE CARCERI DI TUTTI I VIDEOGIOCHI",
+ "SI USA PER FORNIRE ELETTRICIT\267 AGLI APPARECCHI COLLEGATI",
+ "\324 COMPLETAMENTE ARTIGIANALE, VISTO CHE I GIAPPONESI LI FANNO TASCABILI",
// 130
- "NELLA MIA VITA, HO VISTO SOLTANTO UNA VOLTA UNA COSA COS\336 BRUTTA",
- "SMETILLA. NON DICO NULLA PER SE SI ARRABBIA",
+ "SOLO UNA VOLTA NELLA MIA VITA HO VISTO UNA COSA COS\326 BRUTTA",
+ "LASCIA STARE. NON GLI DICO NULLA ALTRIMENTI SI ARRABBIA",
"SEMBRA ABBASTANZA RAZIONALE",
- "\324 UNA FOTO DI PLATONE SCRIVENDO IL SUO DISCORSO PERSO",
- "NON SONO DI QUELLI CHE PARLANO CON POSTERS",
+ "\324 UNA FOTO DI PLATONE MENTRE SCRIVE IL SUO DIALOGO PERDUTO",
+ "NON SONO UNO DI QUELLI CHE PARLANO CON I POSTER",
// 135
"UNA SCRIVANIA MOLTO CARINA",
- "\324 UN DIPLOMA DI CACCIA-CACCIA-VAMPIRI OMOLOGATO DALLA UNIVERSIT\267 DI OXFORD",
- "\324 NOTTE BUIA CON LUNA PIENA",
- "SEMBRA CHE QUESTE VITI NON SONO MOLTO AVVITATE",
- "NON GUARDARE, MA CREDO CHE UNA TELECAMERA NASCOSTA MI ST\267 REGISTRANDO",
+ "\324 UN DIPLOMA DI CACCIA-CACCIA-VAMPIRI APPROVATO DALL'UNIVERSIT\267 DI OXFORD",
+ "\324 UNA NOTTE BUIA CON LUNA PIENA",
+ "SEMBRA CHE QUESTE VITI NON SIANO AVVITATE DEL TUTTO",
+ "NON GUARDARE, MA CREDO CHE UNA TELECAMERA NASCOSTA MI STIA REGISTRANDO",
// 140
- "UN DETETTORE DI TALEE MOLTO MODERNO",
- "NO, IL LABORATORIO SI TROVA NEL SECONDO PIANO",
- "UN BEL TAVOLINO",
- "\324 UN SACCO DI SOLDI CHE NON PUO MANCARE IN UNA AVVENTURA CHE SIA COS\336 IMPORTANTE",
- "IF I WERE A RICHMAN, DUBIDUBIDUBIDUBIDUBIDUBIDUBIDU",
+ "UN RILEVATORE DI PALETTI MOLTO MODERNO",
+ "NO, IL LABORATORIO SI TROVA AL SECONDO PIANO",
+ "UN BEL COMODINO",
+ "\324 UN MUCCHIO DI DENARO CHE NON PU\343 MANCARE IN NESSUNA AVVENTURA CHE SI RISPETTI",
+ "SE FOSSI RICCO, DUBIDUBIDUBIDUBIDUBIDUBIDUBIDU",
// 145
- "SONO DELLE STRANE FOGLIE. DEVONO AVERLE PORTATE DALLA SUDAMERICA",
- "NON CREDO CHE SIA RISPOSTO",
- "\324 UN BEL CROCIFISSO DI LEGNO. LA ICONA NON RIFLESSA TUTTA LA SUA BELLEZA",
- "IO SOLO PREGO PRIMA DI ANDARMENE AL LETTO",
- "-EH, SEMBRA CHE QUESTO SPUNZONE \324 UN PO ALLENTATO!",
+ "SONO DELLE STRANE FOGLIE. DEVONO AVERLE PORTATE DAL SUDAMERICA O GI\353 DI L\326",
+ "NON CREDO CHE MI RISPONDEREBBERO",
+ "\324 UN MERAVIGLIOSO CROCIFISSO DI LEGNO. L'ICONA NON RIFLETTE TUTTA LA SUA BELLEZZA",
+ "IO PREGO SOLAMENTE PRIMA DI CORICARMI",
+ "EH, PARE CHE QUESTA SBARRA SIA UN PO' ALLENTATA!",
// 150
- "E POI TI LAMENTI PERCHE NON TI DO SUGGERIMENTI",
- "\324 UNO SPUNZONI ABBASTANZA CONVENZIONALE",
- "SONO CARINI, SEBBENE HANNO PARECHIO POLVERE",
- "NO, NON MI SENTIRANO; HI,HI,HI -CHE BUONO!",
- "\"LA BELLA ADDORMENTATA DEL BOSCO\" DI CIAIKOSKY, O CIOIFRUSKY, O COME SI DICA",
+ "E POI TI LAMENTI PERCH\220 NON TI DO SUGGERIMENTI",
+ "\324 UNA SBARRA ABBASTANZA CONVENZIONALE",
+ "SONO CARINI, SEBBENE SIANO RICOPERTI DA UN PO' DI SCHIFEZZE",
+ "NO, NON MI SENTIRANNO. HI,HI,HI CHE BUONO!",
+ "\"LA BELLA ADDORMENTATA NEL BOSCO\" DI CHAIKOSKY, O CHOIFRUSKY, O COME SI DICE",
// 155
"MOLTO APPETITOSA",
- "NO, IO NON SONO DI QUELLI CHE SI METTONO IN BOCCA GOMME USATE",
- "UNA FALCE MOLTO CARINA. MI DOMANDO DOVE CI SAR\265 IL MARTELLO",
- "\"I FABBRICANTI DI TABACCO AVVERTONO CHE IL TABACCO NUOCE GRAVEMENTE LA SALUTE\"",
- "UNA CANDELA NORMALE, ANZI CON CERA",
+ "NO, NON SONO UNO DI QUELLI CHE SI METTONO IN BOCCA GOMME USATE",
+ "UNA FALCE MOLTO CARINA. MI CHIEDO DOVE SIA IL MARTELLO",
+ "I FABBRICANTI DI TABACCO AVVERTONO CHE LE AUTORIT\267 SANITARIE NUOCCIONO GRAVEMENTE ALLA SALUTE",
+ "UNA CANDELA ASSOLUTAMENTE NORMALE, CON CERA E TUTTO",
// 160
- "MAMMA MIA COME BRILLANO QUESTE DUE BRILLANTI MONETE",
- "MAMMA MIA COME BRILLA QUESTA BRILLANTE MONETA",
- "CON QUESTO SAR\220 IMMUNE AI MORSI DEI VAMPIRI",
- "NO, ANCORA NON \220 IL MOMENTO",
- "C'E UN BIGLIETTO DI DIECIMILA E UN PAIO DI MONETE",
+ "ACCIDENTI COME SONO LUCENTI QUESTE DUE MONETE!",
+ "ACCIDENTI COM'\324 LUCENTE QUESTA MONETA!",
+ "CON QUESTO SAR\343 IMMUNE AL MORSO DEI VAMPIRI",
+ "NO, ANCORA NON \324 IL MOMENTO",
+ "C'E UN BIGLIETTO DA MILLE E UN PAIO DI MONETE",
// 165
- "DICE \"SI PREGA DI NON BUTTARE CIBO AL PIANISTA\"",
- "OMELETTA, 3.000 .PESCI FRITI, 2.000,PATATINE, 2.500",
- "LE MIGLIORI HAMBURGUER A QUESTA PARTE DEL DANUBIO, SOLTANTO PER 4.000",
- "UN BEL TESCHIO, CON UNO SGUARDO MOLTO PENETRANTE. HI,HI,HI, CHE BUONO!",
- "CIAO TESCHIO, MI RICORDI AL ZIO DI HAMLET",
+ "DICE \"SI PREGA DI NON TIRARE CIBO AL PIANISTA\"",
+ "OMELETTE, 200. PESCE FRITTO, 150, PATATINE CON MAIONESE, 225",
+ "I MIGLIORI HAMBURGER DI QUESTA RIVA DEL DANUBIO, SOLTANTO PER 325!",
+ "\324 UN BEL TESCHIO, CON UNO SGUARDO MOLTO PENETRANTE. HI, HI, HI, BUONA QUESTA!",
+ "CIAO TESCHIO, MI RICORDI LO ZIO DI AMLETO",
// 170
- "HO L'ABITUDINE DI NON TOCCARE COSE CHE SIANO STATE VIVE",
- "UN CESTINO",
- "UN TOTOCALCIO PER LA PARTITA DI STASERA",
- "MI DOMANDO CHE CI SAR\265 DIETRO",
- "-EH, QUESTA TENDE NON SI MUOVE!",
+ "HO L'ABITUDINE DI NON TOCCARE COSE CHE SONO STATE VIVE",
+ "\324 UN CESTINO",
+ "\324 UNA SCOMMESSA PER LA PARTITA DI STANOTTE",
+ "MI DOMANDO CHE CI SAR\267 DIETRO",
+ "EH, QUESTA TENDA NON SI MUOVE!",
// 175
- "MADONNA, CHE TETRO \220 QUESTO CASTELLO.",
- "NON CE LA FACCIO, \220 TROPPO LONTANO PER SENTIRMI",
- "UN TIPICO BOSCO TRANSILVANO, CON GLI ALBERI",
- "-MA CHE SCIOCHEZZE DICI, \220 MOLTO BUIO",
- "PASTICCERIA ROSSI. DOLCI E GOMME",
+ "CAVOLI, CHE TETRO QUESTO CASTELLO, EH?",
+ "NON POSSO, \324 TROPPO LONTANO PER SENTIRMI",
+ "\324 UN TIPICO BOSCO TRANSILVANO, CON ALBERI",
+ "CERTO CHE NE SPARI DI SCIOCCHEZZE, CON IL BUIO CHE C'\324!",
+ "NEGOZIO DI DOLCI GARCIA. TORTE E GOMME DA MASTICARE",
// 180
"UNA PORTA MOLTO BELLA",
- "\220 CHIUSA",
- "UN FUSTO COMPLETAMENTE CHIUSO",
+ "\324 CHIUSA",
+ "\324 UN BARILE COMPLETAMENTE SIGILLATO",
"",
- "CHE ANIMALETTI COS\326 BELLI!",
+ "CHE BELLE BESTIOLINE!",
// 185
- "BSSSSSS,BSSSS, GATINO..",
- "NON RISPONDE",
- "LA LUNA \220 UN SATELLITE CHE GIRA INTORNO LA TERRA CON UN PERIODO DI RIVOLUZIONE DI 28 GIORNI",
+ "PSSST, PSSST, GATTINO...",
+ "NON C'\324 RISPOSTA",
+ "LA LUNA \324 UN SATELLITE CHE GIRA INTORNO ALLA TERRA CON UN PERIODO DI RIVOLUZIONE DI 28 GIORNI",
"CIAO, LUNA LUNETTA",
- "\220 TOTALMENTE CHIUSA CON TABELLE",
+ "\324 COMPLETAMENTE SIGILLATA DA DELLE TAVOLE",
// 190
- "IMPOSSIBILE. QUESTO, NON LO APRE N\220 HOUDINI",
- ".EH, SEMBRA CHE L'OMBRA DEL CIPRESSE \220 ALUNGATA",
- "-EOOO, BARISTA",
+ "IMPOSSIBILE. QUESTA NON LA APRE NEANCHE BRACCIO DI FERRO",
+ "EHI, SEMBRA CHE L'OMBRA DEL CIPRESSO SIA ALLUNGATA!",
+ "EHI, BARISTA!",
"VORREI UNA CAMERA",
- "SA DOVE POSSO TROVARE A UNO CHE SI FA CHIAMARE CONDE DRASCULA",
+ "SA DOVE POSSO TROVARE UN CERTO CONTE DRASCULA?",
// 195
- "SI, PER CHE?",
- "COME MAI?",
- "DA.....DAVVERO?",
- "BUONA DOMANDA, GLI RACONTER\220 LA MIA STORIA, SENTA..",
- "SONO SOLTANTO CINQUE MINUTI",
+ "S\326, COSA C'\324?",
+ "AH S\326?",
+ "DA... DAVVERO?",
+ "BELLA DOMANDA. LE RACCONTER\343 LA MIA STORIA. ALLORA...",
+ "SONO SOLO CINQUE MINUTI",
// 200
- "MI CHIAMO JOHN HACKER, E SONO RAPPRESENTANTE DI UNA IMMOBILIARIE BRITANICA",
- "MI HANNO DETTO CHE IL CONDE DRASCULA VUOLE COMPRARE DEI TERRENI A GIBRALTAR, E SONO QU\326 PER NEGOZIARE LA VENDITA",
- "MA CREDO IO CHE DOMANI PRESTO TORNO CON LA MAMMA",
- "BELLA NOTTE, VERO?",
+ "MI CHIAMO JOHN HACKER, E RAPPRESENTO UNA COMPAGNIA IMMOBILIARE BRITANNICA",
+ "SEMBRA CHE IL CONTE DRASCULA VOGLIA COMPRARE DEI TERRENI A GIBILTERRA E MI HANNO MANDATO QUI PER NEGOZIARE LA VENDITA",
+ "MA CREDO CHE DOMATTINA PRESTO TORNER\343 DA MIA MADRE",
+ "BELLA NOTTATA, VERO?",
"NO, NIENTE",
// 205
- "EOOOO, PIANISTA",
- "BELLA NOTTE",
- "ANZI, NON FA FREDDO",
- "ALLORA... TI LASCIO CONTINUARE A SUONARE",
- "VA BENE",
+ "EHI, PIANISTA",
+ "BELLA NOTTATA",
+ "E NON FA NEMMENO FREDDO",
+ "VA BENE, TI LASCIO CONTINUARE A SUONARE",
+ "BENE ALLORA",
// 210
"CIAO CAPO, COME VA?",
"E LA FAMIGLIA?",
- "C'\220 GENTE QU\326, EH?",
- "MEGLIO NON DICO NULLA",
- "SI ST\265 MEGLIO A CASA CHE A NESSUN POSTO... -EH? MA SE LEI NON \220 LA ZIA EMMA. ANZI. SE IO NON HO NESSUNA ZIA EMMA.",
+ "CARINO COME POSTO, EH?",
+ "MEGLIO CHE NON DICA NULLA",
+ "NON C'\324 POSTO PI\353 BELLO DELLA PROPRIA CASA... NON C'\324... EH? MA TU NON SEI LA ZIA EMMA. IN EFFETTI IO NON HO NESSUNA ZIA EMMA!",
// 215
- "SI, IL MIO ANCHE. LEI PUO CHIAMARMI COME GLI PARA, MA SE MI CHIAMA JOHNY, VENGO SUBITO COME I CANI",
- "SI, CHE SPIRITOSO SONO, VERO? MAA.. DOVE MI TROVO?",
- "SI.",
- "MANAGIA..",
- "OH, SI. COME NO",
+ "S\326, ANCHE IL MIO. MI PU\343 CHIAMARE COME PI\353 LE PIACE, MA SE MI CHIAMA JOHNNY, CORRER\343 DA LEI COME UN CAGNOLINO",
+ "S\326, SONO PROPRIO SPIRITOSO, VERO? COMUNQUE, DOVE MI TROVO?",
+ "S\326.",
+ "MANNAGGIA...",
+ "OH, S\326. IMMAGINO DI S\326",
// 220
- "ALLORA GRAZIE MILE PER DARMI IL TUO AIUTO. NON TI DISTURBO PI\351 . SE MI DICI DOV'\220 LA PORTA, PER FAVORE...",
- "PERCHE LA BOTTA HA DOVUTO DAGNARMI IL CERVELLO E NON VEDO UNA MADONNA",
- "NON FA NIENTE. SEMPRE NE PORTO ALTRI IN PI\351 ",
- "-UFFA, CHE FIGA!- NON MI ERA ACCORTO, CERTO, SENZA GLI OCCHIALI",
- "SENTI..",
+ "BEH, GRAZIE PER IL TUO AIUTO. NON TI DISTURBER\343 PI\353 . POTRESTI DIRMI DOV'\324 LA PORTA, PER FAVORE...",
+ "LA BOTTA DEVE AVERMI DANNEGGIATO IL CERVELLO... NON RIESCO A VEDERE UN TUBO...",
+ "BAH, NON IMPORTA. NE PORTO SEMPRE UN PAIO DI RISERVA",
+ "WOW, CHE BELLA RAGAZZA! NON ME NE ERO ACCORTO PRIMA! CERTO, SENZA GLI OCCHIALI!",
+ "SENTI...",
// 225
- "COME MAI...?!",
- "NON TI PREOCUPARE B.J., AMORE MIO! TI LIBERER\220 DA QUEL TIZIO",
- "MI HA FATTO ARRABBIARE",
- ".AHHH, IL LUPO- MANNARO! -MUORE MALDITO!",
- "BENE, CREDO...",
+ "E QUESTOOO?!",
+ "NON TI PREOCCUPARE B.J., AMORE MIO! TI SALVER\343 DALLE SUE GRINFIE",
+ "MI HAI FATTO DAVVERO ARRABBIARE...",
+ "AHHH, UN LUPO MANNARO! MUORI, MALEDETTO!",
+ "S\326, BEH...",
// 230
- "BENE, CREDO CHE PROSSIGUER\220 LA MIA STRADA. PERMESSOO..",
- "-COME?",
- "LA VERIT\267, PENSANDOCI MEGLIO, CREDO DI NO",
- "DIMI, OH ERUDITO FILOSOFO, C'\324 QUALCUNA RELAZIONE CAUSA-EFETTO TRA LA VELOCIT\267 E LA PANCETA?",
- "VA BENE, SMETTILA. COMUNQUE NON SO PERCHE HO DETTO QUESTO",
+ "S\326, BEH... CREDO CHE PROSEGUIR\343 PER LA MIA STRADA. CON PERMESSO...",
+ "COSA?",
+ "PER LA VERIT\267, PENSANDOCI BENE... CREDO DI NO",
+ "DIMMI, O ERUDITO FILOSOFO, ESISTE UNA QUALCHE RELAZIONE CAUSA-EFFETTO TRA LA VELOCIT\267 E LA PANCETTA?",
+ "VA BENE, VA BENE, LASCIA PERDERE. NON SO NEANCHE PERCH\220 L'HO DETTO.",
// 235
- "COSA FAI QU\336 FILOSOFANDO, CHE NON STAI MANGIANDO GENTE?",
+ "PERCH\220 STAI QUI A FILOSOFARE, INVECE DI ANDARE A MANGIARE LE PERSONE?",
"COME MAI?",
- "SENTI, PUOI RIPETERE QUELLO DI \"INCLINAZIONI PRE-EVOLUTIVE\"?",
- "SI SI, QUELLA STORIA CHE MI HAI RACCONTATO PRIMA. PERCHE NON HO CAPITO MOLTO BENE.",
- "NO, MEGLIO NON DICO NULLA, NON VOGLIO METTERE IL COLTELLO NELLA PIAGA...",
+ "SENTI, PUOI RIPETERE QUELLA COSA SULLE RELAZIONI PRE-EVOLUTIVE?",
+ "S\326, AMICO. QUELLA MENATA CHE MI HAI FATTO SENTIRE PRIMA. \324 CHE NON L'HO CAPITA MOLTO BENE...",
+ "NO, MEGLIO NON DIRE NULLA, NON VOGLIO METTERE IL COLTELLO NELLA PIAGA...",
// 240
- "SI, MI DICA?",
- "SI, CHE SUCCEDE?",
- "AH, ADESSO CHE CITA IL SOGGETTO GLI DIR\343 CHE...",
+ "PRONTO?",
+ "S\326, CHE SUCCEDE?",
+ "AH, VISTO CHE NE PARLA, LE DIR\343 CHE...",
"",
- "AH.., COSA SUCCEDEREBBE SE UN VAMPIRO PRENDEREBBE LA RICETA..",
+ "A PROPOSITO, NON CHE SIA QUESTO IL CASO, CERTO, MA COSA ACCADREBBE SE PER CASO UN VAMPIRO OTTENESSE LA RICETTA?",
// 245
- "NIENTE. SENTI, QUESTO SEMBRA UN POSTICCIO MESSO SUL COPIONE PER FINIRE PRESTO IL VIDEO-GIOCO?. BENE, FORSE, NO",
+ "AD OGNI MODO. SENTI, QUESTA NON TI SEMBRA UNA TROVATA MESSA SUL COPIONE PER FINIRE PRESTO IL GIOCO? BEH, FORSE NO",
"\324 VUOTO!",
- "PERCHE HAI RUBATO IL MIO AMORE, B.J., SENZA LEI LA MIA VITA NON HA SENSO",
- "-IL SUO CERVELLO?!",
- "NO NIENTE, MA CREDO CHE ALLA FINE IL TUO PICCOLINO MOSTRO MI HA FATTO ARRABBIARE",
+ "PERCH\220 MI HAI RUBATO IL MIO UNICO AMORE, B.J.? SENZA DI LEI LA MIA VITA NON HA SENSO",
+ "IL SUO CERVELLO?!",
+ "NON PER NIENTE, MA CREDO DI AVERNE ABBASTANZA DEL TUO MOSTRICIATTOLO",
// 250
- "SANTA MADONNA AIUTAMI!",
- "NON TE LA CAVEREI. SICURO CHE APPARISCE SUPERMAN E MI LIBERA!",
- "CHE SCHIFFO DI VIDEO-GIOCO NEL CUI MUORE IL PROTAGONISTA",
- "UN ATTIMO, COSA SUCCEDE COL MIO ULTIMO DESIDERIO?",
- "-HA,HA! ORA SONO IMMUNIZZATO CONTRO TE, MALEDETTO DEMONIO. QUESTA SIGARETTA \324 UNA POZIONE ANTI-VAMPIRI CHE MI HA DATTO VON BRAUN",
+ "SANTA VERGINE, SALVAMI DA ALTRE SFORTUNE!",
+ "NON TE LA CAVERAI. SICURAMENTE APPARIR\267 SUPERMAN E MI SALVER\267!",
+ "CHE SCHIFO DI GIOCO \324 QUESTO, UNO IN CUI MUORE IL PROTAGONISTA!",
+ "EHI, UN MOMENTO, COSA NE \324 DEL MIO ULTIMO DESIDERIO?",
+ "AH, AH! ORA SONO IMMUNIZZATO CONTRO DI TE, MALEDETTO DEMONIO. QUESTA SIGARETTA CONTIENE UNA POZIONE ANTI-VAMPIRO CHE MI HA DATO VON BRAUN",
// 255
- "SI CERTO. MA NON RIUSCIRAI MAI A FARMI DIRTI LA RICETA",
- "POSSO SOPPORTARE LA TORTURA, ANZI CREARLA",
- "-NO, PER FAVORE!- PARLER\220, MA NON FARMI QUESTO!",
- "BENE, TI HO GI\267 DETTO QUELLO CHE VOLEVI SAPERE. ORA LIBERA B.J. E ME, E LASCIACI PERDERE",
- "-B.J-.! COSA FAI QU\336? DOV'\324 DRASCULA?",
+ "S\326, CERTO. MA NON RIUSCIRAI MAI A FARMI DIRE LA RICETTA",
+ "POSSO SOPPORTARE QUALUNQUE TORTURA.",
+ "NO, TI PREGO! PARLER\343, MA NON FARMI QUESTO!",
+ "BENE. TI HO DETTO QUELLO CHE VOLEVI SAPERE. ORA LIBERA B.J. E ME, E LASCIACI IN PACE!",
+ "B.J.! COSA CI FAI QUI? DOV'\324 DRASCULA?",
// 260
- "CHE PERVERSO! SOLTANTO PERCH'\324 NOBILE PENSA CHE HA IL DIRITTO SU TUTTI QUANTI",
- "ABASSO LA ARISTOCRAZIA!",
- "FORZA I POVERI DEL MONDOOO...",
- "E QUELLO CHE VEDO \324 CHE TI HA INCATENATO ANZI CON LUCCHETTO",
- "O.K., NON AVRAI UNA FONCINA?",
+ "CHE SPREGEVOLE! SOLTANTO PERCH\220 APPARTIENE ALLA NOBILT\267 PENSA DI AVERE LO \"IUS PRIMAE NOCTIS\" SU QUALUNQUE RAGAZZA LUI VOGLIA",
+ "ABBASSO IL DISPOTISMO ARISTOCRATICO!",
+ "FORZA I POVERI DEL MONDOOO...!",
+ "A QUANTO VEDO TI HA INCATENATO CON LUCCHETTO E TUTTO, EH?",
+ "VA BENE. NON HAI UNA FORCINA?",
// 265
- "BENE BENE, NON PRENDERTELA COS\336, CI PENSER\220 IO",
- "EH, BARISTA",
+ "VA BENE, VA BENE. NON PRENDERTELA COS\326, MI VERR\267 IN MENTE QUALCOSA.",
+ "EHI, BARISTA!",
"COME VA LA PARTITA?",
"CHI?",
- "MA NON VEDI CHE DRASCULA \324 QU\336?",
+ "MA NON VEDI CHE DRASCULA \324 QUI?",
// 270
- "ANDIAMO A UCCIDERLO",
- "SERVIMI UN DRINK..",
+ "ALLORA LA FINIAMO CON LUI UNA VOLTA PER TUTTE, NO?",
+ "SERVIMI UN DRINK",
"NIENTE. HO DIMENTICATO COSA VOLEVO DIRTI",
- "O\247MI\247SERVI\247UN\247DRINK\247O\247MI\247METTO\247A\247SUONARE\247IL\247PIANOFORTE",
- "QUANTO MANCA PER LA FINE DELLA PARTITA?",
+ "O MI SERVI UN DRINK O MI METTO A SUONARE IL PIANOFORTE FINO ALLA FINE DELLA PARTITA",
+ "QUANTO MANCA ALLA FINE DELLA PARTITA?",
// 275
"BUONA SERA",
- "COME VA IGOR? VAI CON LA GOBBA? -HI,HI,HI,CHE BUONO!",
- "CHE STAI FACENDO?",
- "NO",
+ "E COME TI SENTI, IGOR? UN PO' INGOBBITO? AH, AH, AH, CHE SPASSO!",
+ "COSA STAI FACENDO?",
+ "BEH, NO",
"ALLORA METTITI GLI OCCHIALI",
// 280
- "COSA \324 QUELLA DELLA ORGIA SOPRANNATURALE?",
- "VA BENE, NON COTINUARE, MI FACCIO IDEA",
- "NON POTREI DIRMI DOV'\324 DRASCULA?",
- "DAIII, PER FAVORE",
- "PER CHE NO?",
+ "COS'\324 QUESTA STORIA DELL'ORGIA SOPRANNATURALE?",
+ "OK, OK, NON CONTINUARE, ME NE SONO FATTO UN'IDEA",
+ "NON POTRESTI DIRMI DOV'\324 DRASCULA?",
+ "DAAAI, PER FAVORE...!",
+ "PERCH\220 NO?",
// 285
"AH, MA DORME DI NOTTE?",
- "BENE, ALLORA IN BOCCA IL LUPO CON I REDDITI",
- "DEVO PROPRIO PARLARE CON LUI",
- "EOOOO, SCHELETROOO!",
- "OH DIO! UN MORTO CHE PARLA!",
+ "BENE, ALLORA IN BOCCA AL LUPO CON I REDDITI",
+ "DEVO PARLARE CON LUI",
+ "EHI, SCHELETROOO!",
+ "SANTO CIELO! UN MORTO CHE PARLA!",
// 290
- "RACCONTAMI. COME MAI SEI VENUTO QU\336?",
- "E PER CHE DRASCULA VUOLE CREARE UN MOSTRO?",
+ "RACCONTAMI. COME SEI FINITO QUI?",
+ "E PERCH\220 DRASCULA VUOLE CREARE UN MOSTRO?",
"COME TI CHIAMI, AMICO SCHELETRO?",
- "SENTI, NON VUOI QUALCOSA DA MANGIARE?",
- "DEVI AVERE LO STOMACO VUOTO .- HI,HI,HI!",
+ "SENTI, NON VUOI CHE TI PORTI QUALCOSA DA MANGIARE?",
+ "DEVI AVERE LO STOMACO VUOTO. AH, AH, AH!",
// 295
- "LA VERIT\267 \324 CHE NON MI VA DI PARLARE ADESSO",
- "VANFFAN ( BIP ) FIGLIO DI .......( BIIP ).. VAI A FARE....( BIIIP )",
- "IO LA AMAVO DAVVERO. O.K., SONO D'ACCCORDO CHE NON ERA MOLTO INTELLIGENTE, MA NESSUNO \324 PERFETTO, NO?",
- "ANZI, AVEVA UN CORPO DA PAURA",
- "ORMAI NON SAR\343 PI\353 QUELLO DI PRIMA .MI RICHIUDER\343 IN UN MONASTERO, E LASCIER\343 LA MIA VITA PERDERE",
+ "ADESSO NON MI VA DI PARLARE",
+ "CHE FIGLIA DI ...(BIP). VADA A FARSI F...(BIP) QUELLA STR...(BIP)!",
+ "IO LA AMAVO DAVVERO. VA BENE, NON ERA PROPRIO UN'INTELLETTUALE, MA NESSUNO \324 PERFETTO, NO?",
+ "E POI, AVEVA UN CORPO MOZZAFIATO",
+ "NON SAR\343 MAI PI\353 QUELLO DI PRIMA. MI RINCHIUDER\343 IN UN MONASTERO E LASCER\343 SCORRERE VIA LA MIA VITA A POCO A POCO",
// 300
- "NIENTE POTR\267 FARMI USCIRE DI QUESTA MISERIA PERCHE...",
+ "NIENTE POTR\267 TIRARMI FUORI DA QUESTA MISERIA PERCH\220...",
"DI CHI? DI CHI?",
- "VOGLIO ESSERE PIRATA",
- "VOGLIO ESSERE PROGRAMMATORE",
+ "VOGLIO ESSERE UN PIRATA",
+ "VOGLIO ESSERE UN PROGRAMMATORE",
"RACCONTAMI QUALCOSA SU GARIBALDI",
// 305
- "CONTINUER\343 A GIOCARE E DIMENTICHER\343 CHE VI HO VISTI",
- "MA CHI AVR\267 PENSATO QUESTA SCIOCHEZZA!",
- "\324 UNA BORSA COME QUELLA DI MIA NONNA",
- "MA CHE FIGO SONO!",
- "PI\353 MI VEDO PI\353 MI PIACCIO",
+ "CONTINUER\343 A GIOCARE E DIMENTICHER\343 DI AVERVI VISTO",
+ "A CHI SAR\267 VENUTA IN MENTE QUESTA IDIOZIA?",
+ "\324 UNA BORSETTA COME QUELLA DI MIA NONNA",
+ "PER\343, CHE FIGO CHE SONO!",
+ "PI\353 MI VEDO, PI\353 MI PIACCIO",
// 310
"E POI COME MI CHIUDO?",
- "PRIMA DEVO APRIRMI, VERO?",
- "ST\343 BENE DOVE SONO",
- "MI HO GI\267 PRESSO",
- "CIAO IO",
+ "PRIMA DOVR\343 APRIRMI, NO?",
+ "STO BENE DOVE SONO",
+ "MI SONO GI\267 PRESO",
+ "CIAO ME!",
// 315
- "ME GLI INDOSSER\343 QUANDO SIA LA OCCASIONE OPORTUNA",
- "NON VEDO NIENTE DI SPECIALE",
- "\324 BENE DOV'\324",
- "E PER CHE?",
- "NON CE LA FACCIO",
+ "LI INDOSSER\343 QUANDO SAR\267 IL MOMENTO GIUSTO",
+ "NON CI VEDO NIENTE DI SPECIALE",
+ "STA BENE DOV'\324",
+ "E PERCH\220?",
+ "NON POSSO",
// 320
- "CIAO TU",
- "\324 IL SEPOLCRO DELLO ZIO PEPPINO",
- "EOOOO, ZIO PEPPINOOOO!",
- "NO.NON VOGLIO TAGLIARMI UN' ALTRA VOLTA",
- "-EHEM,EHEM..!",
+ "CIAO A TE",
+ "\324 IL SEPOLCRO DELLO ZIO DESIDERIO",
+ "EHI, ZIO DESIDERIOOOO!",
+ "NO. NON VOGLIO TAGLIARMI UN'ALTRA VOLTA",
+ "EHEM, EHM...!",
// 325
- "GNAMM, EMMM,!",
- "-SI, COF, COF!",
- "GUARDA, C'\324 UNA GOMMA QU\336 ATTACATA",
+ "GNAMM, AH!",
+ "S\326, COF, COF!",
+ "GUARDA, C'\324 UNA GOMMA ATTACCATA QUI",
"\324 IL TELEFONINO CHE MI HANNO REGALATO A NATALE",
- "COM'\324 ALTO",
+ "COM'\324 ALTO!",
// 330
- "ESCI AL BALCONE GIULIETTA!",
- "TU SEI LA LUCE CHE ILLUMINA LA MIA VITA!",
- "EH, PORTA, CHE C'\324?",
- "EOOOO, SPENDITRICE DI TABACCO DI TRANSILVANIAAA",
- "\324 UNA SPENDITRICE DI TABACCO",
+ "ESCI SUL BALCONE, GIULIETTA!",
+ "TU SEI LA LUCE CHE ILLUMINA LA MIA STRADA!",
+ "EHI, PORTA, DOVE PORTI?",
+ "EHI, DISTRIBUTORE DI SIGARETTE DI TRANSILVANIA!",
+ "\324 UN DISTRIBUTORE DI SIGARETTE",
// 335
"HO UN'ALTRA MONETA DENTRO",
- "NO. HO DECISSO SMETTERE DI FUMARE E DI BERE",
- "DA OGGI SAR\343 SOLTANTO PER LE DONNE",
- "QUESTO \324 UNA TRUFFA! NON \324 USCITO NULLA",
- "ALLA FINE!",
+ "NO. HO DECISO DI SMETTERE DI FUMARE E DI BERE",
+ "A PARTIRE DA ADESSO MI DEDICHER\343 SOLAMENTE ALLE DONNE",
+ "QUESTA \324 UNA TRUFFA! NON \324 USCITO NULLA!",
+ "FINALMENTE!",
// 340
- "CHE TI HO DETTO?, UN BAULE",
- "CIAO BAULE, TI CHIAMI COME MIO CUGINO CHE SI CHIAMA RAUL..E",
- "HO TROVATO LA BORSA DI B.J.",
- "MIO DIO, NON MI RIFLETTO, SONO UN VAMPIRO!",
- "...AH, NO, \324 UN DISEGNO",
+ "CHE TI HO DETTO? UN BAULE",
+ "CIAO BAULE, TI CHIAMI QUASI COME MIO CUGINO... RAULE.",
+ "HO TROVATO LA BORSA DI B.J.!",
+ "MIO DIO, NON HO UN RIFLESSO, SONO UN VAMPIRO!",
+ "...AH, NO. \324 UN DISEGNO!",
// 345
- "SPECCHIO DELLE MIE BRAME: CHI \220 ILPI\351 BELLO DEL REAME?",
+ "SPECCHIO, SPECCHIO DELLE MIE BRAME: CHI \324 IL PI\353 BELLO DEL REAME?",
"NON VUOLE APRIRMI",
- "MOLTO BENE. MI HO MESSO I TAPPI",
- "\324 UN DIPLOMA DI CACCIA-VAMPIRI OMOLOGATO DALLA UNVERSIT\267 DI CAMBRIDGE",
- "NO. MANCANO ANCORA GLI INGREDIENTI, NON MERITA LA PENA CHE SIA SVEGLIATO",
+ "MOLTO BENE. HO MESSO I TAPPI",
+ "\324 UN DIPLOMA DI CACCIA-VAMPIRI APPROVATO DALL'UNIVERSIT\267 DI CAMBRIDGE",
+ "NO, MANCANO ANCORA ALCUNI INGREDIENTI, NON VALE LA PENA SVEGLIARLO",
// 350
- "NON HO SOLDI",
- "\324 UNA LAMPADA BRITANICA",
+ "MA NON HO SOLDI",
+ "\324 UNA LAMPADA BRITANNICA",
"BARISTA! AIUTAMI!",
- "HA COMPARITO UN VAMPIRO ED HA PRESSO LA MIA FIDANZATA",
- "MA NON MI AIUTER\267",
+ "\324 COMPARSO UN VAMPIRO ED HA PRESO LA MIA FIDANZATA!!",
+ "MA NON MI AIUTERAI?!",
// 355
- "MORTA? CHE VUOLE DIRE?",
- "- EHEM!",
- "UN VAMPIRO HA SEQUESTRATO LA RAGAZZA DELLA 506!",
- "DEVI AIUTARMI!",
- "NON SAI SUONARE NESSUNA DI \"ELIO E LE STORIE TESSE\"",
+ "MORTA? COSA INTENDI DIRE?",
+ "EHEM!",
+ "UN VAMPIRO HA RAPITO LA RAGAZZA DELLA 506!",
+ "MA MI DEVI AIUTARE!",
+ "NE SAI SUONARE QUALCUNA DI ELIO E LE STORIE TESE?",
// 360
- "COME TI SOPPORTI, SUONANDO SEMPRE LO STESSO?",
- "ALLORA COME MI SENTI?",
- "PRESTAMI I TAPPI",
+ "COME FAI A RESISTERE SUONANDO SEMPRE LO STESSO PEZZO TUTTO IL GIORNO?",
+ "E ALLORA COME FAI A SENTIRMI?",
+ "PRESTAMI I TAPPI PER LE ORECCHIE",
"DAI, TE LI RESTITUISCO SUBITO",
"DAIIII...",
// 365
- "CIAO. DEVO UCCIDERE UN VAMPIRO",
+ "BEH, CIAO. HO UN VAMPIRO DA UCCIDERE",
"",
- "COSA DICI? IN TRANSILVANO?",
- "CHI \324 LO ZIO PEPPINO?",
- "MA CHE SUCCEDE CON DRASCULA?",
+ "MA COME PARLI? IN TRANSILVANO?",
+ "CHI \324 LO ZIO DESIDERIO?",
+ "MA COSA \324 SUCCESSO CON DRASCULA?",
// 370
- "CHI \324 VON BRAUN?",
- "E PER CHE NON LO FA?",
+ "CHI \324 QUESTO VON BRAUN?",
+ "E PERCH\220 NON LO FA?",
"E DOVE POSSO TROVARE VON BRAUN?",
- "GRAZIE E CIAO, SOGNI D'ORO",
- "SAR\267 MEGLIO BUSSARE PRIMA",
+ "GRAZIE E CIAO, DORMI BENE",
+ "SAR\267 MEGLIO SUONARE PRIMA",
// 375
- "\324 LEI IL PROFESSORE VON BRAUN?",
- "E MI POTREBBE DIRE DOVE POSSO ...?",
- "NON CREDO SIA IL NANNO GANIMEDI",
- "-PROFESSORE!",
- "AIUTAMI! LA VITA DEL MIO AMORE DIPENDE DI LEI!",
+ "\324 LEI IL PROFESSOR VON BRAUN?",
+ "E MI POTREBBE DIRE DOVE POSSO...?",
+ "NON CREDO SIA IL NANO GANIMEDE",
+ "PROFESSORE!",
+ "MI AIUTI, LA PREGO! LA VITA DELLA MIA AMATA DIPENDE DA LEI!",
// 380
- "VA BENE, NON HO BISOGNO DEL SUO AIUTO",
- "O.K. ME NE VADO",
- "NON AVERE PAURA. INSIEME VINCEREMO DRASCULA",
- "ALLORA PER CHE NON MI AIUTA?",
- "IO CE LE HO",
+ "E VA BENE, NON HO BISOGNO DEL SUO AIUTO",
+ "D'ACCORDO. ME NE VADO",
+ "NON ABBIA PAURA. INSIEME SCONFIGGEREMO DRASCULA",
+ "ALLORA PERCH\220 NON MI AIUTA?",
+ "IO LE HO",
// 385
- "SI CE LE HO",
+ "ECCOME SE LE HO!",
"D'ACCORDO",
- "...EHH...SI",
- "VENGO A RIENTRARE A QUESTA CABINA",
- "SONO PRONTO PER FARE LA PROVA",
+ "...EHH ...S\326",
+ "SONO VENUTO PER ENTRARE DI NUOVO IN QUELLA CABINA",
+ "SONO PRONTO PER AFFRONTARE LA PROVA",
// 390
- "VA BENE, VECCHIETO. SONO VENUTO PER IL MIO SOLDI",
- "NO, NIENTE. ME NE GI\267 ANDAVO",
+ "E VA BENE, VECCHIETTO. SONO VENUTO PER I MIEI SOLDI",
+ "NO, NIENTE. ME NE STAVO ANDANDO",
"SCUSA",
- "TI \324 INTERESANTE QUESTO LIBRO? HA PARTITURE DI TCIAKOWSKY",
+ "TI INTERESSA QUESTO LIBRO? HA LE PARTITURE DI TCHAIKOWSKY",
"COME POSSO UCCIDERE UN VAMPIRO?",
// 395
- "NON TI HANNO DETTO CHE NON \324 BUONO DORMIRE IN CATTIVA POSIZIONE?",
- "\324 QUELLO CHE SEMPRE DICE MIA MADRE",
- "PER CHE DRASCULA NON FU RIUSCITO A UCCIDERTI?",
- "E COSA FU?",
- "BENISSIMO! HA LEI LA POZIONE DI IMMUNIT\267...!",
+ "NON TI HANNO DETTO CHE DORMIRE IN UNA BRUTTA POSIZIONE NON \324 SALUTARE?",
+ "\324 QUELLO CHE MI DICEVA SEMPRE MIA MADRE",
+ "PERCH\220 DRASCULA NON RIUSC\326 AD UCCIDERTI?",
+ "E COSA NE FU?",
+ "FANTASTICO! LEI HA LA POZIONE DELL'IMMUNIT\267...!",
// 400
- "ALLORA",
+ "E ALLORA?",
"MOLTO BENE",
- "MI PUO RIPETERE COSA BISOGNO PER QUELLA POZIONE?",
- "VADO VIA VELOCE A TROVARLO",
- "SENTA, COSA \324 SUCCESO CON IL PIANISTA?",
+ "MI PU\343 RIPETERE DI COSA HO BISOGNO PER QUELLA POZIONE?",
+ "OK, CORRO A TROVARLO",
+ "SENTA, COSA \324 SUCCESSO CON IL PIANISTA?",
// 405
"HO GI\267 TUTTI GLI INGREDIENTI DI QUESTA POZIONE",
- "UNA DOMANDA: COSA \324 QUELLA DI ALUCSARD ETEREUM?",
- "DICA, DICA..",
+ "SOLO UNA DOMANDA: COS'\324 QUELLA SCRITTA ALUCSARD ETEREUM?",
+ "DICA, DICA... ",
"E DOV'\324 QUELLA GROTTA?",
- "CHE C'\324? NON AVETE TRIBUNALE?",
+ "CHE C'\324? NON AVEVATE UN TRIBUNALE?",
// 410
- "...MA ...E SE TROVO PI\353 VAMPIRI?",
+ "...MA ...E SE TROVO ALTRI VAMPIRI?",
"\324 UN VAMPIRO CHE NON MI FA PASSARE",
- "SI ASSOMIGLIA A YODA, MA PI\353 ALTO",
- "EH, YODA. SE MI FAI PASSARE TI DAR\343 CENTO LIRE",
- "BENE, O.K., NON POSSO DIRTI NULLA",
+ "ASSOMIGLIA A YODA, MA UN PO' PI\353 ALTO",
+ "EHI, YODA. SE MI FAI PASSARE TI DAR\343 UN PENNY",
+ "OK, CALMA, CERTO CHE CON TE NON SI PU\343 PROPRIO PARLARE",
// 415
+ "TI HANNO MAI DETTO CHE ASSOMIGLI A YODA?",
"CIAO VAMPIRO, BELLA NOTTE, VERO?",
- "TI HANNO DETTO QUALCHE VOLTA CHE TI ASSOMIGLII A YODA?",
- "SEI UN VAMPIRO O UN DIPINTO ALL'OLEO?",
- "MEGLIO NON DIRTI NIENTE, PERCHE POI TI ARRABBII",
- "\324 CHIUSA CON LA CHIAVE",
+ "SEI UN VAMPIRO O UN DIPINTO A OLIO?",
+ "MEGLIO NON DIRE NIENTE, ALTRIMENTI POI TI ARRABBI",
+ "\324 CHIUSA A CHIAVE",
// 420
- "SE PROVO, LA GAZZA MI POTREI CAVARE UN OCCHIO",
+ "SE CI PROVO LA GAZZA POTREBBE CAVARMI UN OCCHIO!",
"\324 CHIUSA! DIO MIO, CHE PAURA!",
- "LE CERNIERE SONO OSSIDATE",
- "LA DENTRO C'\324 SOLTANTO UN BARATOLO DI FARINA",
- "QUESTO HA TOLTO L'OSSIDO",
+ "I CARDINI SONO ARRUGGINITI",
+ "QUI DENTRO C'\324 SOLTANTO UN CESTO DI FARINA",
+ "QUESTO HA TOLTO LA RUGGINE",
// 425
- "HO TROVATO UNA TALEA DI LEGNO DI PINO",
- "PRENDER\343 QUESTO CH'\220 PI\353 GROSSO",
- "BENE, CREDO DI POTERE TOGLIERMI QUESTO STUPIDO COSTUME",
- "\"CORRIDOIO AI TORRIONI CHIUSO PER LAVORI IN CORSO. PER FAVORE, PER LA PORTA PRINCIPALE. SCUSATE PER IL DISTURBO\"",
- "..\324 PALLIDO, HA DENTI CANINI, HA CIUFFO E UTILIZA MANTELLO...- SICURO CH'\324 DRASCULA!",
+ "HO TROVATO UN PALETTO DI LEGNO DI PINO",
+ "PRENDER\343 QUESTO QUI PI\353 GROSSO",
+ "BENE, CREDO DI POTERMI TOGLIERE QUESTO STUPIDO COSTUME",
+ "\"CORRIDOIO AI TORRIONI CHIUSO PER LAVORI IN CORSO. USATE LA PORTA PRINCIPALE. SCUSATE IL DISTURBO\"",
+ "...\324 PALLIDO, HA I CANINI IN FUORI, PORTA IL TOUPET E INDOSSA IL MANTELLO... \324 SICURAMENTE DRASCULA!",
// 430
- "B.J., B.J., STAI BENE?",
- "SI, SO CH'\324 SCEMA MA MI SENTO SOLISSIMO",
- "NON AVRAI UNA CHIAVE PER CASO, VERO?",
- "- E SICURO CHE NON HAI UN GRIMALDELLO?",
- "DAMI UNA FONCINA. VADO A FARE COME MCGYVER",
+ "\324 B.J.! STAI BENE, B.J.?",
+ "S\326, LO SO CHE \324 TONTA, MA SONO COS\326 SOLO",
+ "NON \324 CHE HAI UNA CHIAVE, EH?",
+ "E SCOMMETTO CHE NON HAI NEANCHE UN GRIMALDELLO...",
+ "DAMMI UNA FORCINA. GIOCHER\343 A FARE MCGYVER!",
// 435
"NON MUOVERTI, TORNO SUBITO",
- "- MANAGIA!- SI \324 ROTTA!",
- "OLE, ANCHE MI HO FATTO LA BARBA!",
- "SI, CARO?",
- "NON ARRIVA",
+ "MANNAGGIA! SI \324 ROTTA!",
+ "OLEEEE! MI SONO FATTO PERSINO LA BARBA!",
+ "S\326, TESORO?",
+ "NON \324 ANCORA ARRIVATO",
// 440
- "IL PIANISTA NON C'\324",
+ "IL PIANISTA NON \324 QUI",
"UN DRINK TRANSILVANO",
- "ANCORA NON HO CAMERA",
- "SEMBRA CHE FU RISUCCHIATO NELLO SCARICO DELLA VASCA E HA DECISO APRIRE UN BAR",
- "\324 UBRIACO PERSO",
+ "NON HO ANCORA UNA CAMERA",
+ "SEMBRA CHE SIA RIMASTO INCASTRATO NELLA VASCA DA BAGNO E ABBIA DECISO DI APRIRE UN BAR",
+ "\324 UBRIACO FRADICIO",
// 445
- "QUESTI CAPELLI.... CREDO CHE MI FANNO RICORDARE A QUALCUNO",
+ "QUESTO CAPELLO... MI RICORDA QUALCUNO",
"\324 UNO SCHELETRO OSSUTO",
- "GUARDA! MIGUEL BOSE!",
- "\324 ADDORMENTATO. SAREBBE UN PECCATO SVEGLIARGLI",
- "\324 PI\353 BRUTTO CHE BEGNINI",
+ "GUARDA! C'\324 MIGUEL BOSE!",
+ "STA DORMENDO. SAREBBE UN PECCATO SVEGLIARLO",
+ "\324 PI\353 BRUTTO DI EMILIO FEDE",
// 450
- "UN FERETRO DI LEGNO DI PINO",
- "MI TAGLIER\267 A FETTINI, COME UN SALSICCIOTTO",
- "NON MI PIACCIONO I PENDOLI. PREFERISCO LE CARCIOFE",
- "LE MIE MANI SONO LEGATE. NON CE LA FAR\343",
- "\324 OVVIO CH'\324 UNA PORTA SEGRETA",
+ "UNA BARA IN LEGNO DI PINO",
+ "MI TAGLIER\267 A FETTINE, COME UN SALSICCIOTTO",
+ "NON MI PIACCIONO I PENDULI. PREFERISCO GLI ALCACHOFAS",
+ "HO LE MANI LEGATE. NON POSSO FARCELA",
+ "OVVIAMENTE \324 UNA PORTA SEGRETA",
// 455
"MI IGNORANO",
- "-DAIII!",
- "NEL PRIMO COPIONE SI MUOVEVA, MA IL VIDEO-GIOCO \220 USCITO DAL BUDGET E NON HANNO POTUTO PAGARMI UNA PALESTRA E NON SONO GONFFIATO",
- "SEMBRA CH'\324 UN P\343 ALLENTATA DAL MURO",
- "NON CREDO CHE MI SIA UTILE. \324 TROPPO UMIDA PER ACCENDERLA.",
+ "DAIII!",
+ "SECONDO IL COPIONE SI SAREBBE DOVUTO MUOVERE, MA IL BUDGET ERA RISICATO, NON MI HANNO PAGATO LA PALESTRA E COS\326 NON HO POTUTO FARMI I MUSCOLI. FINE DELLA STORIA",
+ "SEMBRA UN PO' STACCATA DALLA PARETE",
+ "NON PENSO CHE MI TORNER\267 UTILE. \324 TROPPO UMIDA PER ACCENDERSI",
// 460
- "AL LATO OVEST? -N\324 PAZZO, CHI SA CHE CI SAR\267 LI!",
- "HA DEI BELLI DISEGNI TRANSILVANI",
+ "ALL'ALA OVEST? \324 DA PAZZI! CHISS\267 COSA POTRESTI TROVARCI!",
+ "HA DELLE OTTIME MOTIVAZIONI TRANSILVANE",
"",
- "CHE PENA CHE NON CI SIA DENTRO UN AGNELLINO ARRROSTANDOSI",
- "LA ULTIMA VOLTA CHE APRII UN FORNO, LA CASA SALT\220 PER ARIA",
+ "PECCATO CHE NON CI SIA UN BELL'AGNELLO ARROSTO, L\326 DENTRO",
+ "L'ULTIMA VOLTA CHE HO APERTO UN FORNO HO FATTO SALTARE IN ARIA LA CASA",
// 465
- "LO SCUDO DELLA SCUADRA DI CALCIO DI TRANSILVANIA",
- "E PER CHE? PER INDOSARLA SULLA TESTA?",
- "NON CREDO CHE I CASSETI SIANO DI QUELLI CHE SI APPRONO",
- "NON VOGLIO SAPERE IL CIBO CHE CI SAR\267 LA DENTRO!",
- "HO L'IMPRESSIONE CH'\324 IMPRESSIONISTA",
+ "LO STEMMA DELLA SQUADRA DI CALCIO TRANSILVANA",
+ "E PERCH\220? PER METTERMELA SULLA TESTA?",
+ "NON CREDO CHE QUESTI CASSETTI SIANO DI QUELLI CHE SI APRONO",
+ "NON VOGLIO SAPERE CHE RAZZA DI CIBO CI SIA L\267 DENTRO",
+ "MI D\267 L'IMPRESSIONE DI ESSERE IMPRESSIONISTA",
// 470
- "LA NOTTE SI IMPADRONA DI TUTTI QUANTI... CHE PAURA?",
- "\324 OSTACOLATA",
- "\324 IL RE, NON LO AVEVI IMAGINATO?",
- "NO, NE UNO A CASA, ANZI GLI DO DA MANGIARE",
- "UNA SCAFFALATURA CON LIBRI ED ALTRE COSE",
+ "LA NOTTE CALA SU OGNUNO DI NOI... NON \324 TERRIFICANTE?",
+ "\324 INCASTRATA",
+ "\324 IL RE. LUI NON TE LO SEI IMMAGINATO, VERO?",
+ "NO, NE HO GI\267 UNO A CASA DA SFAMARE",
+ "UNO SCAFFALE CON LIBRI ED ALTRE COSE",
// 475
- "E A CHI CHIAMO A QUESTE ORE?",
- "\"COME FARE LA DECLARAZIONE DI REDDITI\"- CHE INTERESSANTE!",
- "NE HO UNO A CASA, CREDO CH'\324 UN BEST-SELLER MONDIALE",
- "UNA CHIAVE COMPLETAMENTE NORMALE",
- "MI SA QHE QUESTA NON \220 DI QU\336",
+ "MA CHI POTREBBE MAI CHIAMARE A QUEST'ORA?",
+ "\"COME COMPILARE LA DICHIARAZIONE DEI REDDITI\". MOLTO INTERESSANTE!",
+ "NE HO GI\267 UNO A CASA. CREDO SIA UN BEST SELLER MONDIALE",
+ "UNA CHIAVE ASSOLUTAMENTE NORMALE",
+ "NON CREDO CHE SIA DI QUESTA ZONA",
// 480
- "EH, SONO PATATINE FRITE A FORMA DI DENTI CANINI ! MI AFASCINA",
- "NON CREDO CHE SIA IL MOMENTO MIGLIORE PER METTERSI A MANGIARE DOLCI, L'ESSERE PI\353 CATTIVO DEL MONDO ha nelle sue mani la mia fidanzzata",
- "COME MI ST\343 DIVERTENDO UCCIDENDO VAMPIRI CON QUESTO!",
- "VEDIAMO SE APPARISCE UN ALTRO PRESTO",
- "NO, DEVE ESSERE CON UN VAMPIRO SPORCO E SCHIFFOSO COME QUELLO DI PRIMA",
+ "EHI, SONO PATATINE FRITTE A FORMA DI DENTI CANINI! LE ADORO!",
+ "NON CREDO SIA IL MOMENTO GIUSTO PER METTERMI A MANGIARE SCHIFEZZE, CONSIDERATO IL FATTO CHE LA MIA FIDANZATA \324 NELLE MANI DELL'UOMO PI\353 CATTIVO DELLA TERRA",
+ "ME LA STO DAVVERO SPASSANDO AD UCCIDERE VAMPIRI CON QUESTO!",
+ "VEDIAMO SE NE APPARE UN ALTRO",
+ "NO, DEV'ESSERE UN VAMPIRO SUDICIO E MALEODORANTE COME QUELLO CHE HO UCCISO PRIMA",
// 485
- "\324 L'AUTENTICA PARRUCA CHE UTILIZZ\343 ELVIS QUANDO DIVENT\343 PELATO",
- "\220 FARINA MA NON POSSO DIRE MARCHE",
- "FORSE IN UN ALTRO MOMENTO. OK?",
- "\220 UNA ASCIA BUONISSIMA, CHE PENA CHE NON CI SIA QU\336 VICINO NESSUNA TESTA DI VAMPIRO",
- "NO. NEL FONDO SONO UNA BRAVISSIMA PERSONA",
+ "\324 L'AUTENTICA PARRUCCA CHE UTILIZZ\343 ELVIS QUANDO DIVENT\343 PELATO",
+ "\324 FARINA, MA NON POSSO DIRE LA MARCA",
+ "FORSE UN'ALTRA VOLTA, VA BENE?",
+ "\324 UN'ASCIA MAGNIFICA, PECCATO CHE NON CI SIA NEMMENO UNA TESTA DI VAMPIRO QUI INTORNO",
+ "NO. IN FONDO SONO UNA BRAVISSIMA PERSONA",
// 490
- "\324 IL DEODORANTE DELLA TACHER -HI,HI,HI!",
- "\324 UN MANTELLO ABBASTANZA CARINO",
+ "\324 IL DEODORANTE DELLA TATCHER ... AH, AH, AH...!!",
+ "\324 UN MANTELLO MOLTO CARINO",
"",
- "COME TUTTI I RAMI DI TUTTI GLI ALBERI DEL MONDO, CIO\324 MICA SPEZIALE",
- "OH, INCREDIBILE!- UNA CORDA IN UNA AVVENTURA GRAFICA!",
+ "COME I RAMI DI TUTTI GLI ALBERI DEL MONDO. NON CI VEDO NIENTE DI SPECIALE",
+ "OH, INCREDIBILE! UNA CORDA IN UN'AVVENTURA GRAFICA!",
// 495
- "MI DOMANDO A CHE SERVE...",
- "UNA CORDA LEGATA A UNA BRANCA, O UNA BRANCA LEGATA A UNA CORDA, DIPENDE COME SI GUARDI",
- "SEMBRA CHE QUESTA GAZZA HA CATIVE INTENZIONI",
- "DAI.., NON LA DICO NULLA CHE POI SI ARRABBIA",
- "SEMBRA ESSERE MORTA, MA NON \220 VERO - EH?",
+ "MI DOMANDO A COSA POSSA SERVIRE...",
+ "UNA CORDA LEGATA AD UN RAMO O UN RAMO LEGATO AD UNA CORDA, DIPENDE DA COME SI GUARDA",
+ "PARE CHE QUESTA GAZZA ABBIA CATTIVE INTENZIONI",
+ "SCORDATELO, NON DIR\343 NULLA ALTRIMENTI SI ARRABBIA",
+ "MI SEMBRA MORTA, MA NON LO \324 VERAMENTE, VERO?",
// 500
- "NESSUN ANIMALE \220 STATO MALTRATO DURANTE LE RIPRESE DI QUESTO VIDEO-GIOCO",
+ "NESSUN ANIMALE HA SUBITO MALTRATTAMENTI DURANTE LA PRODUZIONE DI QUESTO VIDEOGIOCO",
},
};
@@ -4075,52 +4323,52 @@ const char *_textd[NUM_LANGS][NUM_TEXTD] = {
{
// 0
"",
- "COME VA, IGOR?",
- "-SEMPRE CHE C' UNA BUONA PARTITA SUCCEDE LO STESSO! BENE, ANDREMO A GUARDARLA AL BAR, COME SEMPRE",
- "ADESSO IGOR, ASCOLTA. ANDIAMO A REALIZZARE LA FASE 1 DEL MIO PROGETTO PER CONQUISTARE IL MONDO",
- "ATTRARREMO UN FULMINo DELLA TEMPESTA E LO DISMAGNETIZZAREMO CON L'INDIFIBULATORE. LA ELETTRICIT\265 ANDR\265 AL MIO MOSTRO E, GLI DAR\265 VITA!",
+ "COME STA ANDANDO, IGOR?",
+ "\324 SEMPRE LA STESSA STORIA, OGNI VOLTA CHE C'\324 UNA BELLA PARTITA SUL SATELLITE! COMUNQUE ANDREMO A VEDERLA AL BAR, COME AL SOLITO",
+ "ADESSO ASCOLTA BENE, IGOR, SIAMO ALLA FASE NUMERO UNO DEL MIO PIANO PER LA CONQUISTA DEL MONDO",
+ "ATTIREREMO UN FULMINE E LO DEMAGNETIZZEREMO CON L'INDIFIBULATORE. L'ELETTRICIT\267 VERR\267 TRASFERITA AL MOSTRO E GLI DAR\267 LA VITA!",
// 5
- "SE TUTTO VA BENE QUESTO SAR\265 SOLTANTO IL PRIMO DI UN'IMMENSO ESERCITO CHE CONQUISTAR\265 IL MONDO PER ME, HA,HA,HA",
- "I MOSTRI DISTRUGGERANNO TUTTE LE ARME DI TUTTI GLI ESERCITI DEL MONDO, MENTRE NOI CI RIFURGIAREMO nei miei terreni A GIBRALTAR",
- "POI, FAREMO UN GOLPE, E I GOVERNI DEL MONDO NON AVRANNO PER DIFENDERSI, E AVR\220 LE LORO NAZIONI SOTTO I MIEI PIEDI",
- "SAR\220 IL PRIMO CATTIVO DELLA STORIA CHE RIESCA!",
- "A TE NIENTE, SCIOCCO! ST\220 SPORRENDO LA TRAMA. BENE, TUTTO A POSTO?",
+ "SE TUTTO ANDR\267 PER IL VERSO GIUSTO, QUESTO SAR\267 L'INIZIO DI UN GRANDE ESERCITO CHE CONQUISTER\267 IL MONDO PER ME, AH, AH, AH",
+ "I MOSTRI DISTRUGGERANNO TUTTI GLI ESERCITI DEL MONDO, MENTRE NOI CI RIFUGEREMO IN UNO DEI TERRENI CHE HO COMPRATO A GIBILTERRA",
+ "POI FAREMO UN COLPO DI STATO, I GOVERNI DI TUTTO IL MONDO NON AVRANNO MODO DI DIFENDERSI E SI PROSTRERANNO AI MIEI PIEDI",
+ "SAR\343 IL PRIMO CATTIVO DELLA STORIA A RIUSCIRCI! AH, AH!",
+ "NON STO PARLANDO CON TE, IDIOTA! STO ESPONENDO LA TRAMA. BENE, \324 TUTTO PRONTO?",
// 10
- "-\220 IL MOMENTO! -PREMI L'INTERRUTTORE DELLE BATTERIE ALCALINE!",
- "- PORCA MISERIA! -CHE COSA NON \220 ANDATA BENE?",
- "SEI SICURO DI AVERLO CONTROLLATO BENE? E NO MANCABA NIENTE? ULTIMAMENTE PER I REDDITI NON VEDI UNA MADONNA",
- "IMBECILE!, NON HAI CONETTATO L'INDIFIBULATORE! LE VITI SARANO MAGNETIZZATE E ADESSO AVR\265 IL CERVELLO BRUCIATO",
- "SEI MORTO, SEI MORTO, COME TI PRENDA..",
+ "\324 IL MOMENTO! PREMI L'INTERRUTTORE DELLE BATTERIE ALCALINE!",
+ "PORCA MISERIA! COS'\324 ANDATO STORTO?",
+ "SEI SICURO DI AVERLO CONTROLLATO BENE E CHE NON MANCASSE NULLA? ULTIMAMENTE QUESTA STORIA DELLE TASSE TI STA MANDANDO DAVVERO FUORI DI TESTA",
+ "IDIOTA! HAI DIMENTICATO DI CONNETTERE L'INDIFIBULATORE. PROBABILMENTE LE VITI SI SARANNO MAGNETIZZATE E IL SUO CERVELLO SI SAR\267 ABBRUSTOLITO",
+ "SEI MORTO, SEI MORTO... ASPETTA CHE TI PRENDA!",
// 15
- "STAI ZITTO! DOMANI CERCHER\220 UN ALTRO CERVELLO E RIPETEREMO L'ESPERIMENTO",
- "NO. QUESTA VOLTA NE PORTER\220 UNO DI DONNA, COS\326 SAR\265 NUOVISSIMO, MAI UTILIZZATO. HA, HA HA, CHE BARZELLETA FALLITA",
- "E? SONO IL CATTIVO DELLA STORIA, E SONO MASCHILISTA SE VOGLIO, CAPITO? E NON LAMENTARTI UNA ALTRA VOLTA PERCHE MANGERAI LA TUA GOBBA",
- "HA,HA,HA. UN ALTRO PRESSO. ADESSO PAGHERAI MOLTO CARO QUESTA OFFESA, LA TUA INTENZIONE DI FINIRE CON ME. -IGOR, AL PENDOLO DELLA MORTE!",
- "DIMI, STUPIDO UMANO, COME MAI HAI PENSATO A DISTRUGGERMI?",
+ "STAI ZITTO! DOMANI CERCHER\343 UN ALTRO CERVELLO E RIPETEREMO L'ESPERIMENTO",
+ "NO. QUESTA VOLTA PRENDER\343 UN CERVELLO DI DONNA. PRATICAMENTE NUOVO, MAI UTILIZZATO. AH, AH,AH, BUONA QUESTA. ",
+ "E ALLORA? SONO IO IL CATTIVO DELLA STORIA, E POSSO ESSERE MASCHILISTA QUANTO VOGLIO, CAPITO? E SE DICI ANCORA QUALCOSA TI APPICCICO LA GOBBA IN FRONTE!",
+ "AH, AH, AH, CI SEI CASCATO ANCHE TU!! ADESSO LA PAGHERAI PER AVER OSATO SFIDARMI! IGOR, PORTALO AL PENDOLO DELLA MORTE!",
+ "DIMMI, STUPIDO UMANO, COME MAI VOLEVI DISTRUGGERMI?",
// 20
- "-CHE BELLO!, MI METTEREI A PIANGERE SE NON FOSSE PERCHE MI FA RIDERE",
- "HO BISOGNO DELLA TUA RAGAZZA, IL SUO CERVELLO MI AIUTER\265 A CONQUISTARE IL MONDO",
- "-SI, HA ! VADO A TOGLIARSILO PER METTEGLIELO AL MIO FRUSKYNSTEIN, E CON LUI DOMINER\220 IL MONDO, HA,HA,HA",
- "CHE?! - SEI MORTO, SEI MORTO! TI VADO A...MI HAI FATTO ARRABBIARE. SEI PRONTO PER MORIRE?",
- "HA,HA,HA. TU CREDI?",
+ "CHE BELLO! SE NON MI FACESSE RIDERE, MI METTEREI A PIANGERE",
+ "HO BISOGNO DELLA TUA RAGAZZA, IL SUO CERVELLO MI AIUTER\267 A CONQUISTARE IL MONDO",
+ "S\326, SICURO! LO PRENDER\343 DA LEI E LO DAR\343 AL MIO FRUSKYNSTEIN. IL MONDO SAR\267 NELLE MIE MANI, AH, AH, AH",
+ "COSA!? SEI UN UOMO MORTO! TI FAR\343... MI HAI FATTO VERAMENTE ARRABBIARE... PREPARATI A MORIRE!",
+ "AH, AH, AH. TI PIACEREBBE!",
// 25
- "SI, VERO? HA,HA,HA",
- "VA BENE, PUOI FUMARE LA ULTIMA SIGARETTA, MA SBRIGATI",
- "SONO STUFFO, BUTTA GI\265 LA SIGARETTA!",
- "E DIMI, QUELLA POZIONE HA L'EFFETTO INVERSO?",
- "QUELLO SI VEDR\265 ..",
+ "S\326, VERO? AH, AH AH",
+ "VA BENE, PUOI FUMARTI L'ULTIMA SIGARETTA. MA FAI PRESTO, OK?",
+ "MI HAI STUFATO, BUTTA VIA QUELLA SIGARETTA!",
+ "DIMMI UNA COSA, QUELLA POZIONE HA ANCHE L'EFFETTO OPPOSTO?",
+ "QUESTO LO VEDREMO...",
// 30
- "BENE, SAR\265 VERO?. IGOR, DAMI IL COMPACT DISC DI UNGHIE GRAFFIANDO UNA LAVAGNA",
- "NEANCHE SOGNARLO. LA RAGAZZA RIMANE CON ME, E TU RIMANI LI FINO CHE IL PENDOLO TI TAGLII IN FETTE. HA,HA,HA",
- "MA COME SONO CATTIVO, ANDIAMO IGOR, ANDIAMO A FARE LA POZIONE, ANDIAMO A CONQUISTARE IL MONDO",
+ "OK, ADESSO VEDREMO. IGOR DAMMI IL CD \"UNGHIE CHE GRAFFIANO LA LAVAGNA\"",
+ "NEANCHE PER SOGNO. LA RAGAZZA RIMANE QUI. E TU ASPETTERAI FINCH\220 IL PENDOLO NON TI AVR\267 FATTO A FETTINE. AH, AH, AH",
+ "CAVOLI, SONO DAVVERO CATTIVO... ANDIAMO, IGOR; PREPARIAMO LA POZIONE E CONQUISTIAMO IL MONDO",
"ADESSO CHE SUCCEDE?",
- "SI, CHE C'E?....LA PARTITA!",
+ "S\326, CHE C'\324?... OH DANNAZIONE, LA PARTITA!",
// 35
- "L'AVEVO DIMENTICATA. PRENDI LA RAGAZZA E ANDIAMO A GUARDARE IL CALCIO. CONQUISTER\220 IL MONDO DOPO",
+ "ME L'ERO DIMENTICATA. PRENDI LA RAGAZZA E ANDIAMO A GUARDARCELA. CONQUISTEREMO IL MONDO PI\353 TARDI",
"GRAZIE AMICO, AVEVO SETE",
- "-ARGH! -QUEL CROCIFISSO! -QUEL CROCIFISSO!...",
- "QUE BELLO \220 QUEL CROCIFISSO, NON MI ERO ACCORTO",
- "LASCIAMI, ST\220 GUARDANDO LA PARTITA",
+ "ARGH! QUEL CROCIFISSO! QUEL CROCIFISSO!...",
+ "CHE BELLO QUEL CROCIFISSO, NON L'AVEVO NOTATO",
+ "LASCIAMI IN PACE, STO GUARDANDO LA PARTITA",
// 40
"",
"",
@@ -4141,39 +4389,39 @@ const char *_textd[NUM_LANGS][NUM_TEXTD] = {
"",
// 55
"",
- "Ciao cieco. Come va?.",
- "Come sai che sono straniero.",
- "Sembri un cieco. Hai gli occhiali come il cieco di Sorrento, parli guardando all'infinito come Stevie Wonder..",
- "Bene, scusa. Non sapevo che non vedessi",
+ "CIAO CIECO. COME VA?",
+ "COME SAI CHE SONO UNO STRANIERO?",
+ "SEMBRI UN CIECO. HAI GLI OCCHIALI COME IL CIECO DI SORRENTO, PARLI GUARDANDO ALL'INFINITO COME STEVIE WONDER..",
+ "GUARDA, MI DISPIACE. NON SAPEVO CHE CI VEDESSI",
// 60
- "Ma non mi hai appena detto che non sei cieco?.",
- "- Ma se non vedi!.",
- "Beeeene. Scusa. Allora: Ciao : non vedente",
- "Sono John Hacker, st giocando al Drascula. Tu devi proprio essere il tipico personaggio che mi aiuter in cambio di un oggeto. Vero...?",
- "Ma... Scusa ciec..- non vedente! .Ma.. . che tipo di mestiere il tuo, di dare falci per soldi, mentre suoni la fisarmonica?.",
+ "MA NON MI HAI APPENA DETTO CHE NON SEI CIECO?",
+ "MA SE NON VEDI!",
+ "BEEEENE. SCUSA. ALLORA: \"CIAO NON VEDENTE\"",
+ "SONO JOHN HACKER, STO GIOCANDO A DRASCULA. TU DEVI PROPRIO ESSERE IL TIPICO PERSONAGGIO CHE MI AIUTER\267 IN CAMBIO DI UN OGGETTO. VERO? EH? VERO?",
+ "SCUSA SE TE LO DOMANDO, CIEC... NON VEDENTE! MA... CHE TIPO DI MESTIERE \324 IL TUO, DI DARE FALCI PER SOLDI, MENTRE SUONI LA FISARMONICA?",
// 65
- "Ah, si. \324 vero. Ciao non vedente....(cieco)",
- "Ecco la abbondante quantit di soldi che mi avevi chiesto.",
- "Mi raccomando",
- "Ciao straniero.",
- "E tu... Come sai che sono cieco?",
+ "AH, S\326. \324 VERO. CIAO NON VEDENTE...(CIECO)",
+ "ECCO LA COSPICUA SOMMA DI DENARO CHE MI HAI CHIESTO",
+ "LO SPERO PROPRIO",
+ "CIAO STRANIERO.",
+ "E TU... COME SAI CHE SONO CIECO?",
// 70
- "E tu parli come il figlio di Bill Cosby e non ti offendo.",
- "No, se non vedo.",
- "E non lo sono.",
- "-Oh, certo!. Come non vedo mi chiamano cieco, no?.",
- "-Ciao Straniero! e cosa fai in Transilvania?",
+ "E TU PARLI COME IL FIGLIO DI BILL COSBY E NON TI OFFENDO.",
+ "NO, NON CI VEDO.",
+ "E NON LO SONO.",
+ "OH, CERTO! SICCOME NON CI VEDO TU MI ACCUSI DI ESSERE CIECO.",
+ "CIAO STRANIERO! COSA CI FAI IN TRANSILVANIA?",
// 75
- "Corretto straniero. Per una abbondante quantit di soldi, ti dar in cambio una falce, per quando ne avrai bisogno.",
- "Shhhhhh. Sono trafficante di falci, devo proprio dissimulare.",
- "Perche mi lo hai detto prima, no?",
- "Grazie straniero. Ecco la tua falce. Un oggeto che ti sar molto utile pi avanti...... davvero.",
+ "CORRETTO, STRANIERO. PER UN'ABBONDANTE QUANTIT\267 DI DENARO TI DAR\343 UNA FALCE, PER QUANDO NE AVRAI BISOGNO.",
+ "SHHHHHH. SONO TRAFFICANTE DI FALCI, PER QUESTO DEVO FINGERE.",
+ "PERCH\220 ME LO HAI DETTO PRIMA, NO?",
+ "GRAZIE STRANIERO. ECCO LA TUA FALCE. UN OGGETTO CHE TI SAR\267 MOLTO UTILE PI\353 AVANTI...... DAVVERO.",
"",
// 80
"",
"",
- "No, nada",
- "bla, bla, bla."
+ "NO, NIENTE",
+ "BLA, BLA, BLA.",
},
};
@@ -4261,22 +4509,22 @@ const char *_textb[NUM_LANGS][NUM_TEXTB] = {
{
// 0
"",
- "QU\326, BEVENDO",
- "MORTI TUTTI. GRAZIE. BURRP",
- "SII, CERTO, SICURO..",
- "QUESTA PER IL ZIO PEPPINO",
+ "SONO QUI, STO BEVENDO",
+ "SONO TUTTI MORTI. GRAZIE. BURRP",
+ "S\326, CERTO, SICURO...",
+ "QUESTA \324 PER LO ZIO DESIDERIO",
// 5
- "E QUEST'ALTRA, PER IL CADAVERE DEL ZIO PEPPINO",
- "MIO ZIO. FU ANDATO AL CASTELLO, E NON MAI TORNATO",
- "EEEHH, TORN\220, MA PER POCO TEMPO. SE IL VON BRAUN NON AVESSE SBAGLIATO, MIO ZIO SAREBBE QU\326 BEVENDO",
- "NIENTE..",
- "EEH,SI! QUEL MALVAGIO CI HA INTIMORATI",
+ "E QUEST'ALTRA \324 PER IL CADAVERE DELLO ZIO DESIDERIO",
+ "MIO ZIO. \324 ANDATO AL CASTELLO E NON \324 PI\353 TORNATO",
+ "EH, TORN\343, MA NON TUTTO INTERO. SE VON BRAUN NON AVESSE SBAGLIATO, ADESSO MIO ZIO SAREBBE QUI A BERE CON NOI",
+ "NIENTE...",
+ "EH, S\326! QUEL MALVAGIO CI HA INTIMORITI TUTTI",
// 10
- "A VOLTE SCENDE AL PAESE E QUANDO SE NE VA SI PORTA QUALCUNO",
- "UN P\220 DOPO SOLTANTO TROVIAMO QUALQUE RESTO. CREDO CHE TRAFFICA ORGANI O QUALCOSA DEL GENERE",
- "L'UNICO DEL PAESE CHE SA COME FINIRE CON DRASCULA \220 UNO CHE HA STUDIATO",
- "DA CHE FU SCONFFIGIATO DA DRASCULA SI \220 ALLONTANATO A UNA CAPANNA FUORI DEL PAESE",
- "L'UNICO CHE POTREBBE AIUTARCI A VINCERE DRASCULA, E NON VUOLE SAPERE NIENTE DI NOI. COSA PENSI?",
+ "A VOLTE SCENDE IN PAESE E QUANDO SE NE VA SI PORTA VIA QUALCUNO",
+ "POCO DOPO TROVIAMO SOLTANTO QUALCHE RESTO. CREDO CHE SIA UN TRAFFICANTE DI ORGANI O QUALCOSA DEL GENERE",
+ "\324 L'UNICA PERSONA DEL VILLAGGIO CHE SAPPIA COME FARLA FINITA CON DRASCULA. \324 UNO CHE HA STUDIATO",
+ "DA QUANDO FU SCONFITTO DA DRASCULA VIVE IN UNA BARACCA FUORI DAL PAESE",
+ "LUI \324 L'UNICO CHE POTREBBE AIUTARCI A SCONFIGGERE DRASCULA, MA NON VUOLE SAPERNE. TU CHE NE PENSI?",
},
};
@@ -4432,39 +4680,39 @@ const char *_textbj[NUM_LANGS][NUM_TEXTBJ] = {
{
// 0
"",
- "ST\265 BENE? SENTA, PUO SENTIRMI? SI \220 MORTO?",
- "NO, IL MIO NOME BILLIE JEAN, MA PUOI CHIAMARMI B.J. PI \351 BREVE",
- "HI,HI!- CHE BUONO!",
- "NON SO JOHNY, ERO QU\326, STAVO PER ADDORMENTARMI, QUANDO HO SENTITO UN FORTE RUMORE NEL CORRIDOIO",
+ "TI SENTI BENE? ANDIAMO, SVEGLIATI! RIESCI A SENTIRMI? MA SEI MORTO?",
+ "NO, MI CHIAMO BILLIE JEAN, MA PUOI CHIAMARMI B.J., \324 PI\353 CORTO.",
+ "HI, HI! QUESTA ERA BUONA!",
+ "BEH, JHONNY. VEDI, ME NE STAVO QUA, GI\267 PRONTA PER ANDARE A LETTO, QUANDO HO SENTITO UN FORTE RUMORE IN CORRIDOIO",
// 5
- "PRIMA NON GLI HO DATTO IMPORTANZA, MA DUE ORE DOPO HO SCOPERTO CHE NON RIUSCIVO A ADDORMENTARMI E SONO uscita A FARE QUATTRO PASSI",
- "E FIGURATI LA SORPRESA QUANDO HO APERTO LA PORTA E TI HO TROVATO PER TERRA. TI GIURO, HO PENSATO CH'ERI MORTO..., MA COME SONO SCIOCCA",
- "VOLEVO FARTI IL BOCCA A BOCCA, MA NON C'ERA BISOGNO PERCHE SUBITO HAI COMINCIATO A PARLARE",
- "HAI DETTO NON SO CHE DI UN SPAVENTAPASSERI. CHE COLPO.....!, PERCHE QUANDO UN MORTO SI METTE A PARLARE FA UN COLPO GRANDISSIMO!",
- "VERO DI SI? NON SO COME SONO RIUSCITA, TI HO TRASPORTATO ALLA MIA CAMERA, TI HO MESSO SUL MIO LETTO E.... NIENTE PI\351 .",
+ "ALL'INIZIO NON CI HO FATTO CASO, MA DOPO CIRCA DUE ORE NON RIUSCIVO ANCORA A PRENDERE SONNO E ME NE SONO ANDATA A FARE DUE PASSI",
+ "E IMMAGINA LA MIA SORPRESA QUANDO HO APERTO LA PORTA E TI HO VISTO DISTESO A TERRA. TI GIURO, HO PENSATO CHE FOSSI MORTO... AH, AH, CHE SCIOCCA",
+ "VOLEVO FARTI LA RESPIRAZIONE BOCCA A BOCCA MA NON \324 SERVITO PERCH\220 HAI INIZIATO A PARLARE",
+ "HAI DETTO QUALCOSA A PROPOSITO DI UNO SPAVENTAPASSERI. MI HAI FATTO VENIRE UN COLPO. SAI, \324 ABBASTANZA SCIOCCANTE VEDERE UN MORTO CHE PARLA",
+ "VERO? NON SO COME, MA SONO RIUSCITA A PORTARTI IN CAMERA MIA, TI HO MESSO SUL LETTO E... QUESTO \324 TUTTO... AH, AH, AH.",
// 10
- "NO, NON \220 STATA LA BOTTA, HI, HI. \220 PERCHE ... HO PESTATO I TUOI OCCHIALI",
- "MAMMA MIA MA COM'\220 BELLO CON GLI OCCHIALI! SO CHE NON \220 FERNANDO LANCHA, MA HA QUALCOSA CHE MI PIACE MOLTISSIMO",
- "SI,SI, VOGLIO... ABBRACIAMI FORTE, BACIAMI MOLTO..",
- "OH JOHNY, CARO, MENO MALE CHE SEI VENUTO. QUEL MALVAGIO, DRASCULA, MI HA LEGATO AL LETTO E POI SE NE \220 ANDATO A GUARDARE LA PARTITA",
- "SI, \220 VERO, LIBERAMI",
+ "NO, NON \324 STATA LA BOTTA, HI, HI. \324 CHE PER SBAGLIO HO PESTATO I TUOI OCCHIALI",
+ "MAMMA MIA COM'\324 BELLO CON GLI OCCHIALI! SO CHE NON \324 ANTONIO BANDERAS, MA HA QUALCOSA CHE MI PIACE MOLTISSIMO",
+ "S\326, S\326, LO VOGLIO... ABBRACCIAMI FORTE, BACIAMI...",
+ "OH JOHNNY, CARO, MENO MALE CHE SEI QUI. DRASCULA, QUEL MALEDETTO, MI HA LEGATA AL LETTO E POI SE NE \324 ANDATO A GUARDARE LA PARTITA",
+ "S\326, \324 VERO, LIBERAMI",
// 15
- "NO, MI DISPIACE. HO UTILIZZATO TUTTE IN CARCERE PROBANDO LIBERARMI QUANDO TU MI AVEVI LASCIATA",
- "JOHNY, SEI TU? - BENISSIMO. LO SAPEVO ",
- "NON TI FIGURI QUANTO MI HA FATTO SOFFRIRE DRASCULA",
- "PRIMA MI HA PORTATO VOLANDO FINO QUA E POI MI HA RICHIUSA IN QUESTA CAMERACCIA CHE NON HA N\220 UNO SPECCHIO",
- "COME HAI SENTITO. E LO PEGLIORE: N\220 UNA VOLTA SI \220 SCUSATO",
+ "NO, MI DISPIACE. LE HO USATE TUTTE NELLA CELLA CERCANDO DI LIBERARMI QUANDO MI HAI ABBANDONATA",
+ "JOHNNY, SEI TU? OH, GRAZIE AL CIELO, SAPEVO CHE SARESTI VENUTO!",
+ "NON IMMAGINI NEMMENO QUANTO QUEL MALVAGIO DI DRASCULA MI ABBIA FATTO SOFFRIRE",
+ "PRIMA MI HA PORTATO FIN QUA VOLANDO E POI MI HA RINCHIUSA IN QUESTA CAMERACCIA CHE NON HA NEANCHE UNO SPECCHIO",
+ "\324 QUELLO CHE TI STO DICENDO! E IL PEGGIO \324 CHE NON SI \324 MAI SCUSATO, NEMMENO UNA VOLTA",
// 20
- "JOHNY, CARO. DOVE SEI?",
- "SONO PRONTA, FAMI USCIRE DA QU\326 ",
- "ASPETTA, VADO A GUARDARE... NO CARO, MI DISPIACE",
- "PRENDI..",
- "\"CARO JOHNY:",
+ "JOHNNY, CARO. DOVE SEI?",
+ "SONO PRONTA, FAMMI USCIRE DA QUI",
+ "ASPETTA CHE CONTROLLO... NO, CARO, MI DISPIACE",
+ "PRENDI...",
+ "\"CARO JOHNNY",
// 25
- "MAI POTR\220 DIMENTICARTI, MA NON SAREMO MAI FELICI INSIEME. SAR\220 SINCERA CON TE : C'\220 NE UN ALTRO; PI\351 ALTO, PI\351 FORTE..",
- "ANZI MI HA LIBERATO DA DRASCULA. MI HA CHIESTO LA MANO E HO DETTO DI SI",
- "ADIO JOHNY. NON CERCARE UNA SPIEGAZIONE, PERCHE L'AMORE \220 CIECO.",
- "SPERO NON MI ODII, E RICORDA CHE ANCORA TI VOGLIO BENE, SEBBENE SOLO COME UN AMICO\"",
+ "NON POTR\343 MAI DIMENTICARTI, MA NON SAREMO MAI FELICI INSIEME. SAR\343 SINCERA CON TE: C'\324 UN ALTRO; PI\353 ALTO, PI\353 FORTE...",
+ "MI HA LIBERATO DA DRASCULA. MI HA CHIESTO LA MANO E HO DETTO DI S\326",
+ "ADDIO JOHNNY. NON CERCARE UNA SPIEGAZIONE, PERCH\220 L'AMORE \324 CIECO.",
+ "SPERO CHE NON MI ODIERAI, E RICORDA CHE TI VOGLIO BENE, SEBBENE TU PER ME SIA SOLTANTO UN AMICO\"",
},
};
@@ -4597,33 +4845,33 @@ const char *_texte[NUM_LANGS][NUM_TEXTE] = {
{
// 0
"",
- "EO, LEI",
- "MA CHE DICI!",
- "SONO VIVO, MA HO SEMPRE MOLTA FAME, SA LEI?",
- "IO ERO IL BEONE DEL PAESE, DEGNO SUCCESSORE DI UNA FAMIGLIA DI ILLUSTRI BEONI, E UNA NOTTE DRASCULA MI SEQUESTR\220 PER RUBARMI GLI ORGANI",
+ "EHI, LEI!",
+ "NON RACCONTARMI CERTE CAVOLATE SU UN CADAVERE, OK?",
+ "SONO VIVO. STO SOLO MORENDO DI FAME",
+ "IO ERO L'UBRIACONE DEL PAESE, DEGNO SUCCESSORE DI UNA FAMIGLIA DI ILLUSTRI UBRIACONI, E UNA NOTTE DRASCULA MI RAP\326 PER RUBARMI GLI ORGANI",
// 5
- "mi utilizza COME UNO SCASSO, OGNI VOLTA CHE HA BISOGNO DI QUALCOSA PER IL MOSTRO CHE ST\265 CREANDO VIENE QUA E MI LO toglia",
- "AL INIZIO MI FACEVA MALE, MA ORA NON FA NIENTE",
- "NON SO, SAR\265 LA SUA TESINA DI FINE DI LAUREA",
- "IL MIO NOME PEPPINO, PER SERVIRGLI",
- "LA VERIT\265 CHE NON HO MOLTA VOGLIA, COMUNQUE GRAZIE MILE, SIGNORE",
+ "SICCOME L'ALCOL MI MANTIENE IN VITA, MI TIENE QUI COME UNA SCORTA. OGNI VOLTA CHE HA BISOGNO DI QUALCOSA PER IL MOSTRO CHE STA CREANDO, VIENE DA ME E SE LO PRENDE",
+ "ALL'INIZIO FACEVA MALE, MA ORA NON SENTO PI\353 NULLA",
+ "NON SO, MAGARI SAR\267 LA SUA TESI DI LAUREA",
+ "IL MIO NOME \324 DESIDERIO, PER SERVIRVI",
+ "LA VERIT\267 \324 CHE NON HO MOLTA VOGLIA, COMUNQUE GRAZIE MILLE, SIGNORE",
// 10
- "SI, PROPRIO TU",
- "PER CHE TUTTI I VIDEO-GIOCHI D' AVVENTURE FINISCONO CON UN'ALBEGGIARE O UN TRAMONTO?",
- "E TUTTI QUESTI NOMI SONO DI CHI HANNO FATTO IL GIOCO?",
- "E NON SI VERGOGNANO DI USCIRE ED ESSERE VISTI DA TUTTI QUANTI?",
- "UFFA, SOLTANTO ESCI \"EMILIO DE PAZ\"",
+ "PROPRIO TU!",
+ "PERCH\220 TUTTI I GIOCHI D'AVVENTURA FINISCONO SEMPRE CON UN'ALBA O UN TRAMONTO?",
+ "E TUTTI QUESTI NOMI SONO DI CHI HA FATTO IL GIOCO?",
+ "E NON SI VERGOGNANO A FARSI VEDERE DA TUTTI?",
+ "CAVOLI, QUELL'EMILIO DE PAZ \324 DAPPERTUTTO!!",
// 15
"DAVVERO?",
- "SI",
- "NON \220 PER METTERSI COS\326 ",
- "CERTO LUPO-MANNARO..",
- "... MA NON SEI CADUTO DA UNA FINESTRA E TI HAI FATTO MALE?",
+ "S\326",
+ "BEH, NON NE FARE UNA QUESTIONE",
+ "CERTO, LUPO MANNARO...",
+ "... MA NON TI SEI FATTO MALE CADENDO DA UNA FINESTRA?",
// 20
- "SE PER UNA VOLTA NON FOSSENO SEMPRE GLI STESSI",
- "QUELLO \220 GIA USCITO QUATRO VOLTE",
- "MI PIACEREBBE ESSERE TOP MODEL",
- "SI, E TU, COSA VAI A FARE?",
+ "SE PER UNA VOLTA NON FOSSERO SEMPRE GLI STESSI",
+ "QUELLO \324 GIA USCITO QUATTRO VOLTE",
+ "MI PIACEREBBE ESSERE UN MODELLO",
+ "S\326, E TU COSA FARAI?",
},
};
@@ -4800,44 +5048,44 @@ const char *_texti[NUM_LANGS][NUM_TEXTI] = {
{
// 0
"",
- "MAESTRO, CREDO CHE QUESTO NON VA",
- "SICURISSIMO, MAESTRO",
- "SCUSI, MAESTRO",
- "VA A PORTARE UN ALTRO SCIENTIFICO PAZZO? GLI AVVERTO CHE IL LABORATORIO PIENO E NE ABBIAMO TUTTI SCADUTI",
+ "PADRONE, CREDO NON STIA FUNZIONANDO",
+ "SICURISSIMO, PADRONE",
+ "MI DISPIACE, PADRONE",
+ "HAI INTENZIONE DI ATTIRARE ALTRI SCIENZIATI PAZZI? IL LABORATORIO \324 GI\267 PIENO, E TRA L'ALTRO SONO TUTTI SCADUTI.",
// 5
- "ZITTO, MAESTRO, FIGURASI SE LE SENTONO LE FEMMINISTE",
- "ACCIDENTI!",
- "-MAESTRO! NON LE ASPETTAVO COS\326 PRESTO!",
- "MALE MAESTRO, DEVONO CI ESSERE PROBLEMI CON IL SATELLITE E NON RIESCO A SINTONIZZARE L'IMMAGINE. ANZI LA TEMPESTA CAUSA INTERFERENZE",
- "CHE NE SO, MAESTRO",
+ "ZITTO, PADRONE, LE FEMMINISTE POTREBBERO SENTIRLA",
+ "DANNAZIONE!",
+ "PADRONE! NON LA ASPETTAVO COS\326 PRESTO!",
+ "MALE, PADRONE; DEV'ESSERCI UN PROBLEMA CON IL SATELLITE E NON RIESCO A SINTONIZZARE L'IMMAGINE. SEMBRA CHE LA TEMPESTA CAUSI INTERFERENZE",
+ "NON SAPREI, PADRONE",
// 10
- "SI, MAESTROl",
- "MAESTRO",
+ "S\326, MIO PADRONE",
+ "PADRONE",
"SA CHE ORE SONO?",
- "EH? -AH, CHE COLPO! TU SEI QUELLO DI \"PULIZIA NOTTURNA\" NO?",
- "IO SONO IGOR, IL MAGGIORDOMO. PUOI COMINCIARE NEL SALOTTO DI BALLO, IERI C'ERA ORGIA SOPRANATURALE ED \220 PIENO DI MERDA",
+ "COSA? AH, MI HAI SPAVENTATO! TU SEI IL \"RAGAZZO DELLE PULIZIE NOTTURNE\" GIUSTO?",
+ "SONO IGOR, IL MAGGIORDOMO. PUOI COMINCIARE DALLA SALA DA BALLO. IERI \324 STATA TEATRO DI UN'ORGIA SOPRANNATURALE ED OGGI \324 RIDOTTA AD UNA MERDA.",
// 15
"SE HAI BISOGNO DI QUALCOSA, COMPRALA",
- "LA DECLARAZIONE DI REDDITI, NON VEDI?",
- "NEANCH'IO, I NUMERI SONO PICCOLISSIMI E ANZI, IO NON VEDO BENE DA LONTANO",
- "NEANCHE PARLARNE, MI FANNO SEMBRARE BRUTTO",
- "\220 UNA FESTA CHE FA IL MAESTRO PER I SUOI AMICI OGNI VOLTA CHE ARRIVA QUALCHE IMBECILE CHE VUOLE FINIRE CON LUI",
+ "\324 LA DICHIARAZIONE DEI REDDITI, NON VEDI?",
+ "NEANCH'IO. I NUMERI SONO PICCOLISSIMI E NON CI VEDO MOLTO BENE DA LONTANO",
+ "NEANCHE PER SOGNO! MI FANNO SEMBRARE BRUTTO",
+ "\324 UNA FESTA CHE ORGANIZZA IL PADRONE CON I SUOI AMICI OGNI VOLTA CHE ARRIVA QUALCHE IMBECILLE CHE VUOL CERCARE DI UCCIDERLO",
// 20
- "PRIMA, GLI TOGLIANO GLI OCCHI; POI GLI VERSANO SUCCO DI LIMONE, DOPO IL BRUCIORE.......",
+ "PER PRIMA COSA GLI CAVANO GLI OCCHI. POI GLI VERSANO DEL SUCCO DI LIMONE IN MODO CHE BRUCI, POI...",
"NO",
- "COME CHE PER CHE NO? MA TU HAI VISTO CHE ORE SONO?",
- "IN INVERNO, SI",
+ "COME PERCH\220 NO? HAI VISTO CHE ORE SONO?",
+ "IN INVERNO, S\326",
"ARRIVEDERCI",
// 25
- "N\324 PENSARCI",
- "BENE, BASTA PER OGGI. VADO A CENARE",
- "E CHE SEMPRE DIMENTICO CHIUDERE CON LA CHIAVE",
+ "NON PENSARCI NEMMENO!",
+ "BENE, BASTA PER OGGI. VADO A CENA",
+ "DIMENTICO SEMPRE DI CHIUDERE A CHIAVE",
"ACCIDENTI!",
- "EH? -AH! CHE COLPO, MAESTRO, PENSAVO STAVA DURMENDO",
+ "COSA? PADRONE! MI HA SPAVENTATO! PENSAVO STESSE DORMENDO",
// 30
- "ORA MI RICORDO, PRENDA LE CHIAVI DEL SOGGIORNO, COS\326 DOMANI MATTINA NON MI DISTURBA SE VUOLE GUARDARE I CARTONI ANIMATI",
- "HA PRESSO FREDDO UN'ALTRA VOLTA, MAESTRO? SEMPRE GLI DICO CHE METTA IL RISCALDAMENTO",
- "PRENDA UNA ASPIRINA ED A SUDARE. BUONA NOTTE",
+ "OH, A PROPOSITO, HO PRESO LE CHIAVI DEL SOGGIORNO, COS\326 POTR\267 VEDERE I CARTONI ANIMATI DEL MATTINO SENZA SVEGLIARMI",
+ "HA DI NUOVO PRESO IL RAFFREDDORE, PADRONE? DANNAZIONE. \324 ANNI CHE LE DICO DI METTERE IL RISCALDAMENTO",
+ "BENE, PRENDA UN'ASPIRINA E VADA A LETTO A SUDARE. BUONA NOTTE",
},
};
@@ -5010,43 +5258,43 @@ const char *_textl[NUM_LANGS][NUM_TEXTL] = {
{
// 0
"",
- "UN ATTIMO. PERCHE SIAMO DI DIVERSE RAZZE E LA SOCIET\265 DICA CHE SIAMO NEMICI, ANDIAMO A LASCIARCI DOMINARE PER I PI\351 PRIMITIVI ISTINTI?",
- "MA NON SIAMO UNITI DALLA RAGIONE, DALLA ARMA PI\351 PODEROSA E ANCHE PER IL DONO PI\351 PREZIOSO CHE ABBIAMO?",
- "SE IL GIUDIZIO GUIDASSE I NOSTRI PASSI NELLA VITA SENZA LASCIARE POSTO AI SENTIMENTI, CHE MOSTRANO LE NOSTRE INCLINAZIONI PRE-EVOLUTIVI!",
- "NON CREDI CHE SAREMMO PI\351 BEATI SENZA QUESTO LEGAME EMOZIONALE? RISPONDE EFFIMERA CREATURA",
+ "UN ATTIMO. SOLO PERCH\220 APPARTENIAMO A RAZZE DIVERSE E LA SOCIET\267 DICE CHE SIAMO NEMICI, VOGLIAMO LASCIARE CHE SIANO I NOSTRI ISTINTI PI\353 PRIMITIVI A GUIDARCI?",
+ "NON SIAMO FORSE UNITI DALLA RAGIONE? CHE \324 SIA L'ARMA PI\353 PODEROSA SIA IL DONO PI\353 PREZIOSO CHE ABBIAMO?",
+ "AH, SE IL GIUDIZIO GUIDASSE I NOSTRI PASSI NELLA VITA SENZA LASCIARE IL POSTO AI SENTIMENTI CHE MOSTRANO LE NOSTRE INCLINAZIONI PRE-EVOLUTIVE!",
+ "RISPONDI, EFFIMERA CREATURA. NON CREDI CHE SAREMMO PI\353 FELICI SENZA QUESTO LEGAME EMOZIONALE?",
// 5
- "NON PASSI",
- "VEDI? QUESTO UN CHIARO ESEMPIO: TU VUOI PASSARE E PROSEGUIRE LA TUA AVVENTURA ED IO NON POSSO PERMETTERLO",
- "MA DEVE ESSERE CAUSA DI CONFRONTO QUANDO ANCORA NON CI CONOSCIAMO?",
- "CHE TI HO DETTO?",
- "BOH, DIPENDE DI CHE CAPIAMO COME RELAZIONE. CI SONO AUTORI CHE DIFENDONO...",
+ "NON PASSERAI",
+ "VEDI? QUESTO \324 UN CHIARO ESEMPIO: TU VUOI PASSARE E PROSEGUIRE LA TUA AVVENTURA ED IO NON POSSO PERMETTERLO",
+ "DEVE ESSERE DUNQUE MOTIVO DI CONFRONTO TRA NOI, CHE NON CI CONOSCIAMO PER NULLA?",
+ "BENE QUINDI",
+ "BEH, DIPENDE DA COSA INTENDIAMO PER RELAZIONE. ALCUNI AUTORI DIFENDONO...",
// 10
- "LA CACCIA COME FORMA DI SUSSISTENZA \220 UNA ATTIVIT\265 ARCAICA, INCOMPATIBILE CON UNA NATURA SUPERIORE COM'\220 LA MIA: ADESSO SONO VEGETARIANO",
- "TEMPO FA, STAVO MANGIANDO UN TIZIO QUANDO MI SONO MESSO A RIFLETTERE. FU QUANDO LA CONCLUSIONE DI PRIMA ARRIV\220 ",
- "FU DIFFICILE LASCIARE LE MIE VECCHIE ABITUDINI, MA LA MIA ANIMA IRASCIBILE HA VINTO LA CONCUPISCIBILE E NON MANGIO PI\351 DELLA CARNE",
- "NEPPURE IL PIACERE CHE FA UN OSSO, COL SUCCO DELLA PELLE E QUEL SAPORE CHE TI PORTA A POSTI LONTANI E PARADISIACI...",
- "NEMMENO MI TOCCA DA VICINO, DAVVERO",
+ "LA CACCIA COME FORMA DI SUSSISTENZA \324 UNA ATTIVIT\267 ARCAICA, INCOMPATIBILE CON LA MIA ATTUALE NATURA SUPERIORE: SONO DIVENTATO VEGETARIANO",
+ "SONO ARRIVATO A QUESTA CONCLUSIONE TEMPO FA. STAVO MANGIANDO UN TIZIO QUANDO MI SONO MESSO A RIFLETTERE.",
+ "FU DIFFICILE LASCIARE LE MIE VECCHIE ABITUDINI, MA LA MIA ANIMA IRASCIBILE HA AVUTO LA MEGLIO SU QUELLA CONCUPISCENTE E DA ALLORA NON MANGIO PI\353 CARNE",
+ "NEPPURE IL PIACERE DI SUCCHIARE UN OSSO, SENTIRE IL GUSTO DELLA PELLE E IL SAPORE DOLCE DEL MIDOLLO CHE TI PORTA IN POSTI LONTANI E PARADISIACI...",
+ "NEPPURE QUESTO MI TOCCA, DAVVERO",
// 15
"CHE COSA?",
- "NON SO SU CHE MI PARLI, EFFIMERA CREATURA",
- "NON MI INTERESA",
- "GLI ALTRI VIDEO-GIOCHI, NON SO, MA QUESTO \220 PER APPROFITTARE QUESTO BELLO SCHERMO",
+ "NON CAPISCO DI CHE PARLI, EFFIMERA CREATURA",
+ "NON MI INTERESSA",
+ "GLI ALTRI VIDEOGIOCHI, NON SAPREI, MA QUESTO \324 PER SFRUTTARE AL MEGLIO QUESTO BELLO SCHERMO",
"",
// 20
- "IO SI ME VERGOGNAREI",
- "NO, SONO IL NONNO, IL PADRE, IL FIGLIO, E UN AMICO CHE SI CHIAMA COS\326 ",
- "NO, MA SE NON \220 COS\326, SEMBRAR\265 CHE HANNO FATTO IL VIDEO-GIOCO IN CINQUE",
- "BRAVI RAGAZZI",
- "-QUELLO \220 BUONO, QUELLO \220 BUONO!",
+ "IO ME LA PRENDEREI",
+ "NO, SONO IL NONNO, IL PADRE, IL FIGLIO, E UN AMICO CHE SI CHIAMA COS\326",
+ "NO, MA SE NON \324 COS\326, SEMBRER\267 CHE IL VIDEOGIOCO L'ABBIANO FATTO IN CINQUE",
+ "SONO RAGAZZI PROMETTENTI",
+ "\324 BRAVO, \324 BRAVO!",
// 25
"CHIAMAMI COSTANTINO",
- "NON ERO IO, DAI,. ERA IL MIO CONTROFIGURA, IL COYOTE",
- "INSOMMA, MOLTI TITOLI DI CODA",
- "IO NON SO GI\265 QUANTI",
- "ALLORA PEPPINO, CHE VAI FARE ADESSO?",
+ "NON ERO IO, DAI. ERA IL MIO GEMELLO, IL COYOTE",
+ "ALLA FACCIA, CHE TITOLI DI CODA LUNGHI",
+ "HO PERSO IL CONTO",
+ "ALLORA DESIDERIO, CHE FARAI ORA?",
// 30
"MA DOVRESTI DIMAGRIRE",
- "MI APPARTER\220 AL TIBET A RIFLETTERE SUL SENSO DELLA VITA",
+ "MI RITIRER\343 IN TIBET A RIFLETTERE SUL SENSO DELLA VITA",
},
};
@@ -5159,27 +5407,27 @@ const char *_textp[NUM_LANGS][NUM_TEXTP] = {
// 0
"",
"CIAO",
- "BELLA, MOLTO BELLA",
- "NO, CHE NON LO FA",
+ "SISSIGNORE, MOLTO BELLA",
+ "NO CHE NON LO FA",
"VA BENE",
// 5
- "-SI?",
+ "S\326?",
"E?",
- "MI DISPIACE. IL SINDACATODI PIANISTI NON MI DA PERMESSO PER LIBERARE RAGAZZE DALLE MANI DI VAMPIRI",
- "SE LA AVESSE SEQUESTRATA IL LUPO-MANNARO...",
- "SOLTANTO POSSO SUONARE QUESTA CANZONE",
+ "MI DISPIACE. IL SINDACATO DEI PIANISTI NON MI PERMETTE DI SALVARE RAGAZZE DALLE GRINFIE DEI VAMPIRI",
+ "SE FOSSE STATA RAPITA DAL LUPO MANNARO...",
+ "NON POSSO SUONARE ALTRO CHE QUESTA CANZONE",
// 10
- "\324 PERCHE SONO PIANISTA DI CONSERVATORIO E IL TABERNERO NON COMPRA PI\353 PARTITURE",
- "PECCATO.....MI PIACE MOLTISSIMO LA MUSICA CLASSICA!",
- "PERCHE MI HO MESSO TAPPI NEGLI ORECCHII",
- "PERCHE SO LEGGERE LE LABRA",
+ "\324 PERCH\220 SONO PIANISTA DI CONSERVATORIO E IL BARISTA NON COMPRA PI\353 SPARTITI",
+ "E DIRE CHE MI PIACE MOLTISSIMO LA MUSICA CLASSICA!",
+ "PERCH\220 HO I TAPPI NELLE ORECCHIE",
+ "PERCH\220 SO LEGGERE LE LABBRA",
"NOOO",
// 15
- "NO!, NON MI SOPPOROTO!",
+ "NO! NON POSSO ANDARE AVANTI COS\326!",
"HO DETTO DI NOOO!",
- "COSA? SI, SI MI INTERESA, COME NO",
- "ADESSSO POTR\343 SUONARE UN'ALTRA CANZONE, GRAZIE!!",
- "CREDO CHE I MIEI TAPPI ADESSO SONO TUOI",
+ "COSA? CERTO CHE MI INTERESSA",
+ "DEO GRATIAS! ADESSO POTR\343 SUONARE UN'ALTRA CANZONE!",
+ "SUPPONGO CHE ORA POSSA DARTI I MIEI TAPPI",
},
};
@@ -5316,34 +5564,34 @@ const char *_textt[NUM_LANGS][NUM_TEXTT] = {
{
// 0
"",
- "CHE SUCCEDE, CHE SUCCEDE?",
+ "CHE C'\324, CHE C'\324?",
"D'ACCORDO. CAMERA 512. DEVE SALIRE LE SCALE. LA CHIAVE \324 NELLA PORTA",
- "IL CONDE DRASCULA?",
- "NO, NIENTE. QUEL TIZIO HA MALA REPUTAZIONE QU\336",
+ "IL CONTE DRASCULA?!",
+ "NO, NIENTE. \324 SOLO CHE QUEL TIPO HA UNA CATTIVA REPUTAZIONE QUI",
// 5
- "SE DICONO MOLTE COSE SU LUI. COME CH'\324 UN VAMPIRO E SEQUESTRA GENTE PER BERE LA SUA SANGUE",
- "ALTRI DICONO CHE SOLO \324 UN TRAFFICANTE DI ORGANI, PER QUELLO TROVIAMO GENTE SQUARTATA FUORI LE MURA",
- "SONO SOLTANTO CHIACCHIERE. FORSE SIA LE DUE COSE. MA, PERCHE VUOLE TROVARE QUEL TIZIO?",
- "NO, HO MOLTO DA FARE..",
- "VA BENE, MA PERCHE VOGLIO IO, NON PERCHE L'ABBIA DETTO TU",
+ "BEH, CORRONO MOLTE VOCI SUL SUO CONTO. ALCUNI DICONO CHE \324 UN VAMPIRO E RAPISCE LE PERSONE PER SUCCHIAR LORO IL SANGUE",
+ "COMUNQUE, ALTRI DICONO CHE \324 SOLO UN TRAFFICANTE DI ORGANI, ED \324 PER QUESTO CHE SI TROVANO CORPI SQUARTATI NELLE VICINANZE",
+ "CHIARAMENTE SONO SOLTANTO VOCI. \324 PI\353 PROBABILE CHE SIA ENTRAMBE LE COSE. A PROPOSITO, PERCH\220 VUOLE INCONTRARE QUEL TIPO?",
+ "NO, LASCIA PERDERE. HO MOLTO DA FARE...",
+ "VA BENE, OK. MA PERCH\220 LO VOGLIO IO, NON PERCH\220 L'HAI DETTO TU",
// 10
- "ADESSO VINCONO",
- "LASCIAMI IN PACE, O.K.?",
+ "STANNO VINCENDO",
+ "LASCIAMI IN PACE, OK?",
"CERTO, NON SONO CIECO",
- "C'\324 LA TRADIZIONE NEL PAESE DI DIMENTICARE I RANCORI QUANDO C'\324 PARTITA DI CALCIO; PER ANIMARE LA SELEZIONE",
- "TI HO DETTO DI STARE ZITTO, NON RIESCO A SENTIRE",
+ "IN PAESE C'\324 L'USANZA DI DIMENTICARE I RANCORI QUANDO C'\324 UNA PARTITA, PER SOSTENERE LA SQUADRA LOCALE",
+ "E STAI ZITTO UNA BUONA VOLTA. NON RIESCO A SENTIRE",
// 15
- "LASCIAMI IN PACE E NON MI DISTURBARE",
- "\324 APPENA COMINCIATO, ZITTO!",
- "AH, BENE. HO PENSATO CHE SUCCEDEVA QUALCOSA",
- "NO, NON FA NIENTE. ADESSO SICURO CH'\324 GI\267 MORTA",
- "SI \324 MESSO A SUONARE MUSICA CLASSICA ED IO LA ODIO",
+ "INSOMMA, LASCIAMI IN PACE E NON MI DISTURBARE PI\353",
+ "\324 APPENA INIZIATA! STAI ZITTO!",
+ "AH, OK. CREDEVO CHE FOSSE SUCCESSO QUALCOSA",
+ "NO, \324 INUTILE. PROBABILMENTE A QUEST'ORA SAR\267 GI\267 MORTA",
+ "\324 CHE SI \324 MESSO A SUONARE MUSICA CLASSICA. E IO NON LA SOPPORTO",
// 20
- "\324 COME FACCIO PER SENTIRE QUELLO CHE VOGLIO SE L'HO LICENZIATO",
- "E ORA SI METTE BULLO...-E SEMBRAVA PROPRIO SCEMO!",
- "...SENTA! FACCIA ATTENZIONE. IL PAVIMENTO \324 APPENA INCERATO",
- "ZITTO! - STIAMO GUARDANDO LA PARTITA!",
- "DAI! PRENDI",
+ "E SICCOME LO PAGO PERCH\220 SUONI QUELLO CHE VOGLIO IO, L'HO LICENZIATO",
+ "E POI SI \324 MESSO A FARE IL BULLO... SEMBRAVA COS\326 INNOCUO PRIMA, CHE IPOCRITA!",
+ "...A PROPOSITO, FACCIA ATTENZIONE. HO APPENA PASSATO LA CERA",
+ "SILENZIO! STIAMO GUARDANDO LA PARTITA!",
+ "DAI, FORZA! PRENDI.",
},
};
@@ -5664,80 +5912,80 @@ const char *_textvb[NUM_LANGS][NUM_TEXTVB] = {
{
// 0
"",
- "MA CHI BUSSA A QUESTE ORE?",
- "EH...NO,NO. IO SONO IL NANNO GANIMEDI....IL PROFESSORE VON BRAUN NON ABITA QU\336 PI\353",
+ "CHI DIAVOLO \324 A QUEST'ORA?",
+ "OH... NO, NO. IO SONO IL NANO GANIMEDE... IL PROFESSOR VON BRAUN NON VIVE PI\353 QUI",
"NO, NON SO DOV'\324!",
- "HO DETTO VIA!",
+ "VATTENE!",
// 5
- "IMBECILE. ORMAI TROPPO TARDE, SEMRE TARDE",
- "SONO COMPLETAMENTE D'ACCORDO",
+ "IMBECILLE! ORMAI \324 TROPPO TARDI, LO \324 SEMPRE",
+ "SONO TOTALMENTE D'ACCORDO",
"IO, PAURA?",
- "ASCOLTA BENE RAGAZZO: STAI PARLANDO CON L'UNICA PERSONA CHE CONOSCE IL SEGRETO PER VINCERE AI VAMPIRI",
- "NON TUTTI QUANTI POSSONO LOTTARE CON UN VAMPIRO. SI DEVONO AVERE DELLE CARATTERISTICHE SPEZIALI",
+ "ASCOLTA BENE, RAGAZZO: STAI PARLANDO CON L'UNICA PERSONA CHE CONOSCE IL SEGRETO PER AFFRONTARE I VAMPIRI",
+ "NON TUTTI POSSONO COMBATTERE CONTRO UN VAMPIRO. BISOGNA AVERE DELLE QUALIT\267 SPECIALI",
// 10
- "NO CE LE HAI",
- "SICURO CHE NON SCOMMETI TUTTO IL TUO SOLDI!",
- "VA BENE . AVANTI",
- "SE DAVVERO SEI PRONTO PER LOTTARE CONTRO DRASCULA, DEVI POTERE SOPPORTARE TUTTI I RUMORI STRIDENTI E VAMPIRICI",
- "TUTTO CHIARO?",
+ "E TU NON LE POSSIEDI",
+ "SCOMMETTERESTI TUTTI I TUOI SOLDI?",
+ "VA BENE. ENTRA",
+ "SE DAVVERO INTENDI AFFRONTARE DRASCULA, DEVI ESSERE IN GRADO DI SOPPORTARE TUTTI I RUMORI PI\353 STRIDENTI E VAMPIRICI",
+ "\324 CHIARO?",
// 15
- "D'ACCORDO. ASPETTA UN ATTIMO",
- "PER FAVORE, METTETI NEL CENTRO DELLA CAMERA",
- "DOV'\324 HO MESSO IL COMPACT DISC DI \"UNGHIE GRAFFIANDO UNA LAVAGNA\"",
- "MOLTO BENE, ANDIAMO",
- "VEDI? SEI UN INUTILE, COME TUTTI GLI ALTRI",
+ "D'ACCORDO. ASPETTA UN MOMENTO",
+ "PER FAVORE, METTITI AL CENTRO DELLA STANZA",
+ "DOV'\324 CHE HO MESSO IL CD DI \"UNGHIE CHE GRAFFIANO LA LAVAGNA\"?",
+ "MOLTO BENE. SI COMINCIA",
+ "VEDI? SEI UN INCAPACE, COME TUTTI GLI ALTRI",
// 20
- "ORA DAMI IL SOLDI CHE HAI PERSO, E VIA",
- "E NON TORNARE FINO CHE NON SIA COMPLETAMENTE PRONTO",
- "E COSA VUOI TU ADESSO?",
- "DEVO AMMETTERLO... HAI LA STOFFA DI LOTTATORE PER VINCERE DRASCULA",
- "EH..! PRENDI IL TUO SOLDI. SO QUANDO HO SBAGLIATO",
+ "ORA DAMMI I SOLDI CHE HAI PERSO E VATTENE",
+ "E NON TORNARE FINCH\220 NON SARAI COMPLETAMENTE PRONTO",
+ "CHE COSA VUOI ADESSO?",
+ "DEVO RICONOSCERLO... HAI LA STOFFA PER COMBATTERE I VAMPIRI",
+ "A PROPOSITO, PRENDI I TUOI SOLDI. SO RICONOSCERE I MIEI ERRORI",
// 25
- "ADESSO VATENE, VOGLIO DORMIRE UN P\343",
- "QUANDO SIA DISPOSTO A UCCIDERE QUALCHE VAMPIRO, TORNA E TI AIUTER\343 ",
- "QUELLO \324 FACILE. LA LUCE DEL SOLE O UN CROCIFISSO, E L'HAI SCHISCCIATO",
- "CON CHI DEVI FARE MOLTA ATTENZIONE \324 CON DRASCULA. I SUOI POTERI FRISISHNOSTICI GLI FANNO IL PI\353 FORTE DEI VAMPIRI",
- "NON POTREI FARE NULLA SE NON FOSSE PER LA .....",
+ "ADESSO VATTENE, VOGLIO DORMIRE UN PO'",
+ "QUANDO SARAI PRONTO AD AFFRONTARE UN VAMPIRO, TORNA E TI AIUTER\343 COME POSSO",
+ "OH, \324 FACILE. BASTA LA LUCE DEL SOLE O UN CROCIFISSO PER INCENERIRLO",
+ "DEVI INVECE STARE MOLTO ATTENTO A DRASCULA. I SUOI POTERI FRISISNOTICI LO RENDONO IL PI\353 POTENTE DEI VAMPIRI",
+ "SARESTI SPACCIATO, SE NON FOSSE PER LA...",
// 30
"...POZIONE!",
- "CERTO. HAI RAGIONE, SE CONTINUO DORMENDO COS\336 FORSE AVR\343 PROBLEMI DI SCHIENA QUANDO SIA VECCHIO",
- "BENE, \324 VERO CHE FU MEGLIO LOTTATORE DI ME, MA IL MIO STUDIO SU TECNICHE ANTI-VAMPIRI GLI AIUT\343 MOLTISSIMO",
- "HO SCOPERTO UNA POZIONE DI IMMUNUT\267 . TI FA INVULNERABILE AI MORSI DI VAMPIRI, O AI SUOI POTERI FRISISHNOTICI",
- "NO, SCUSA, CE L'EBBI MOLTO TEMPO FA, MA UNA POZIONE COM'ERA LA MIA \324 PERICOLOSA. FIGURATI SE LA AVESSE UN VAMPIRO",
+ "OH, CERTO, HAI RAGIONE! SE CONTINUO A DORMIRE COS\326, FORSE AVR\343 PROBLEMI ALLA SCHIENA QUANDO SAR\343 VECCHIO",
+ "BEH, AMMETTO CHE SI \324 RIVELATO PI\353 FORTE DI ME, MA LA MIA PRINCIPALE SCOPERTA SULLE TECNICHE ANTI-VAMPIRO MI HA COPERTO LE SPALLE",
+ "HO SCOPERTO UNA POZIONE DI IMMUNIT\267 CHE TI RENDE INVULNERABILE A QUALUNQUE MORSO DI VAMPIRO, O AI SUOI POTERI FRISISNOTICI",
+ "NO, MI DISPIACE. CE L'AVEVO UNA VOLTA, MA UNA POZIONE CON QUELLE CARATTERISTICHE \324 PERICOLOSA. IMMAGINA SE CADESSE NELLE MANI DI UN VAMPIRO",
// 35
- "GLI FAREBBE IMMUNE AGLI AGLII, ALLA LUCE DEL SOLE.... PER QUELLO L'HO SCARICATA NEL CESO",
- "TRANQUILLO, MI RICORDO BENISSIMO DI COME RIFARLA",
- "BISOGNO AGLII, CHE NE HO QU\326, DOVRAI PORTARMI UN P\220 DI CERA, NICOTINA, UNA GOMMA, E UNA CARTINA O UN TOVAGLIOLO, O QUALCOSA DEL GENERE",
- "-AH! E COME NO, L'INGREDIENTE PRINCIPALE: DELLE FOGLIE DI UNA STRANA PIANTA CHIAMATA FERDINAN",
- "\324 UNA PIANTA CONVOLVOLO, LE SUE FOGLIE PROPORZIONANO POTERI MAGICI SE SONO TAGLIATE DA UNA FALCE D'ORO",
+ "LO RENDEREBBE IMMUNE ALL'AGLIO E ALLA LUCE DEL SOLE... COS\326 MI SONO LIBERATO DI QUELLA CHE NON HO USATO CON UN METODO ALTAMENTE SCIENTIFICO: GETTANDOLA NELLA TAZZA DEL WATER",
+ "TRANQUILLO, MI RICORDO PERFETTAMENTE COME PREPARARE QUELLA POZIONE",
+ "HO BISOGNO DI AGLIO, CHE HO GI\267 QUI. PER\343 DOVRAI PORTARMI UN PO' DI CERA, DELLA NICOTINA, UNA GOMMA E UNA CARTINA DI SIGARETTA, O UN TOVAGLIOLO O QUALCOSA DEL GENERE",
+ "AH! E, OVVIAMENTE, L'INGREDIENTE PRINCIPALE: LE FOGLIE DI UNA STRANA PIANTA CHIAMATA FERNAN",
+ "SI TRATTA DI UNA PIANTA RAMPICANTE LE CUI FOGLIE ACQUISTANO POTERI MAGICI SE VENGONO TAGLIATE CON UNA FALCE D'ORO",
// 40
- "ALLORA, PORTAMI QUESTE CINQUE COSE E FAR\343 PER TE LA POZIONE",
- "DOPO SAREI PRONTO PER UCCIDERE DRASCULA",
- "RICORDA: CERA, NICOTINA, UNA GOMMA, UNA CARTINA E FOGLIE DI FERDINAN, LA PIANTA, TAGLIATE DA UNA FALCE D'ORO",
- "TI L'HO GI\267 DETTO! FU TUTTO GRAZIE ALLA POZIONE",
- "AH, MOLTO BENE. DUNQUE VADO A FARE LA CAN......LA POZIONE. SAR\267 UN ATTIMINO",
+ "ALLORA, QUANDO AVRAI QUESTE CINQUE COSE, PORTAMELE E TI PREPARER\343 LA POZIONE",
+ "DOPO SARAI PRONTO PER AFFRONTARE DRASCULA",
+ "RICORDA: CERA, NICOTINA, UNA GOMMA, UNA CARTINA E DELLE FOGLIE DI FERNAN, LA PIANTA, TAGLIATE CON UNA FALCE D'ORO",
+ "TE L'HO GI\267 DETTO! FU MERITO DELLA POZIONE",
+ "AH, MOLTO BENE. ALLORA VADO A FARMI LA CAN... LA POZIONE. DAMMI UN MINUTO, OK?",
// 45
- "\324 SOLTANTO UN SORTILEGIO DI PROTEZIONE CONTRO VAMPIRI",
- "L'HO MESSO PER DISSIMULARE CHE IL DISEGNATORE HA DIMENTICATO METTERE LA FINESTRA CHE SI VEDE DA FUORI",
- "BENE, PRIMA DEVI SAPERE COME ARRIVARE AL CASTELLO DRASCULA",
- "C'\324 UNAGROTTA CHE VA AL CASTELLO E CHE UTILIZZA QUEL MATTO FAN DI ELVIS, IGOR, PER SCENDERE AL PAESE TUTTE LA MATTINE",
- "MA FA ATTENZIONE, SEMPRE \220 PROTETTA DA UN VAMPIRO. DOVRAI LIBERARTI DI LUI",
+ "\324 UN INCANTESIMO DI PROTEZIONE CONTRO I VAMPIRI",
+ "L'HO MESSA L\326 PER NASCONDERE IL FATTO CHE IL DISEGNATORE HA DIMENTICATO DI METTERE LA FINESTRA CHE SI VEDE DA FUORI",
+ "BENE, LA PRIMA COSA CHE DEVI SAPERE \324 COME ARRIVARE AL CASTELLO DI DRASCULA",
+ "C'\324 UNA GROTTA CHE PORTA DIRETTAMENTE AL CASTELLO. QUEL MATTO FAN DI ELVIS, IGOR, LA USA PER SCENDERE AL PAESE TUTTE LA MATTINE",
+ "MA FA' ATTENZIONE, \324 SEMPRE PROTETTA DA UN VAMPIRO. DOVRAI LIBERARTI DI LUI",
// 50
- "C'\220 UN VECCHIO POZZO ACCANTO ALLA CAPELLA DEL CIMITERO",
- "SI UTILIZZAVA MOLTO TEMPO FA PER GIUDICARE CASI DI STREGONERIA",
- "SI BUTTAVANO DENTRO ALLE STREGE. SE SI AFFONDAVANO ERANO STREGHE. SE NO, NO",
- "UNA VOLTA BUTTAMMO UNA E GALLEGGI\220, DUNQUE NON SAREBBE UNA STREGA",
- "ORA BEVE LA POZIONE. PECCATO CI SIA SOLTANTO PER UNO",
+ "C'\324 UN VECCHIO POZZO ACCANTO ALLA CAPPELLA DEL CIMITERO",
+ "SI USAVA ANTICAMENTE PER GIUDICARE I CASI DI STREGONERIA",
+ "SI BUTTAVANO LE STREGHE NEL POZZO. SE AFFONDAVANO ERANO STREGHE. SE NO, NO",
+ "UNA VOLTA NE BUTTAMMO GI\353 UNA E NON AFFOND\343. SUPPONGO NON FOSSE UNA STREGA.",
+ "AD OGNI MODO. PRENDI LA POZIONE. BASTA PER UNA VOLTA SOLA",
// 55
- "SAR\265 MEGLIO FUMARLO PROPRIO PRIMA DELLA LOTTA CONTRO DRASCULA",
- "CORRI1",
- "SCUSE!",
- "JOHN HACKER? SONO IL DOTTORE VON BRAUN",
- "SENTA, \220 MOLTO IMPORTANTE, \220 SULLA POZIONE",
+ "\324 MEGLIO CHE LA FUMI APPENA PRIMA DI AFFRONTARE DRASCULA",
+ "CORRI!",
+ "SCUSI!",
+ "JOHN HACKER? SONO IL DOTTOR VON BRAUN",
+ "ASCOLTA, \324 MOLTO IMPORTANTE. RIGUARDA LA POZIONE",
// 60
- "HO TROVATO UN LIBRO SU POZIONI E DICE CHE NON SI DEVE BERE ALCOL DOPO AVERE FUMATO LA POZIONE",
- "L'ALCOL BEVUTO FA REAZIONE CON LE SOSTANZE DELLA POZIONE E ANNULLA I SUOI EFFETTI IN DECIME DI SECONDO",
- "DEVO RIATTACARE. LA POLIZIA MI CERCA. DICONO CHE TRAFFICO DROGHE -IGNORANTI! BENE, ALLORA ADIO E IN BOCA IL LUPO",
+ "STAI ZITTO E LASCIAMI PARLARE. HO TROVATO UN LIBRO SULLE POZIONI E DICE CHE NON SI DEVE BERE ALCOL DOPO AVERE FUMATO LA POZIONE",
+ "L'ALCOL INGERITO REAGISCE CON LE SOSTANZE DELLA POZIONE E ANNULLA I SUOI EFFETTI IN POCHI SECONDI",
+ "MI DISPIACE, MA DEVO RIATTACCARE. LA POLIZIA MI CERCA. DICONO CHE SONO UNO SPACCIATORE. IGNORANTI! BEH, ADDIO E BUONA FORTUNA NEL SALVARE IL MONDO",
},
};
@@ -5768,10 +6016,10 @@ const char *_textsys[NUM_LANGS][NUM_TEXTSYS] = {
"VOIX ET TEXT",
},
{
- "PREMI DI NUOVO SUPR PER COMINZIARE",
- "PRMI DI NUOVO ESC PER USCIRE",
- "SOLO SUONI",
- "SUONI E TESTO",
+ "PREMI DI NUOVO CANC PER RICOMINCIARE",
+ "PREMI DI NUOVO ESC PER USCIRE",
+ "SOLO VOCI",
+ "VOCI E TESTO",
},
};
@@ -5807,10 +6055,10 @@ const char *_texthis[NUM_LANGS][NUM_TEXTHIS] = {
},
{
"",
- "",
- "",
- "",
- ""
+ "RACCONTANO CHE, MOLTI ANNI FA, DRASCULA UCCISE LA MOGLIE DI VON BRAUN. DA ALLORA, CON L'INTENZIONE DI AFFRONTARE IL CONTE, VON BRAUN COMINCI\343 A STUDIARE TUTTO QUELLO CHE TROVAVA SUI VAMPIRI.",
+ "QUANDO PENS\343 DI ESSERE PRONTO, AND\343 AL CASTELLO ED EBBE UN VIOLENTO SCONTRO CON DRASCULA.",
+ "NESSUNO SA COSA ACCADDE LASS\353. MA SEBBENE VON BRAUN FU SCONFITTO, DRASCULA NON RIUSC\326 A UCCIDERLO.",
+ "UMILIATO DALLA SCONFITTA, VON BRAUN SCAPP\343 DAL CASTELLO E DA ALLORA NON HA MAI PI\353 OSATO AFFRONTARE DRASCULA.",
},
};
@@ -5934,7 +6182,7 @@ const char *_textverbs[NUM_LANGS][NUM_TEXTVERBS] = {
"poussez",
},
{
- "esamina",
+ "guarda",
"prendi",
"apri",
"chiudi",
@@ -5966,9 +6214,9 @@ const char *_textmisc[NUM_LANGS][NUM_TEXTMISC] = {
"GOOOOOOOAAAAAAAL!",
},
{
- "HUNCHBACKED",
- "Transilvania, 1993 d.c.",
- "GOOOOOOOAAAAAAAL!",
+ "GOBBO",
+ "Transilvania, 1993 d.c. (dopo cena)",
+ "GOOOOOOOOOOOOOOOL!",
},
};
diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp
index 173ba0f993..c69c38199a 100644
--- a/tools/create_kyradat/create_kyradat.cpp
+++ b/tools/create_kyradat/create_kyradat.cpp
@@ -31,7 +31,7 @@
#include "md5.h"
enum {
- kKyraDatVersion = 28,
+ kKyraDatVersion = 32,
kIndexSize = 12
};
@@ -53,6 +53,8 @@ enum {
#include "malcolm.h"
+#include "lol_demo.h"
+
const Game kyra1FanTranslations[] = {
{ kKyra1, IT_ITA, kTalkieVersion, "d0f1752098236083d81b9497bd2b6989", kyra1FreCD },
GAME_DUMMY_ENTRY
@@ -251,6 +253,11 @@ const ExtractFilename extractFilenames[] = {
{ k3ItemMagicTable, k3TypeRaw16to8, "ITEMMAGIC.MAP" },
{ k3ItemStringMap, kTypeRawData, "ITEMSTRINGS.MAP" },
+ // LANDS OF LORE
+
+ // Demo Sequence Player
+ { lSeqplayIntroTracks, k2TypeSoundList, "S_INTRO.TRA" },
+
{ -1, 0, 0 }
};
@@ -288,7 +295,7 @@ bool getFilename(char *dstFilename, const Game *g, const int id) {
void createFilename(char *dstFilename, const int gid, const int lang, const int special, const char *filename) {
strcpy(dstFilename, filename);
- static const char *gidExtensions[] = { "", ".K2", ".K3" };
+ static const char *gidExtensions[] = { "", ".K2", ".K3", 0, ".LOL" };
strcat(dstFilename, gidExtensions[gid]);
for (const SpecialExtension *specialE = specialTable; specialE->special != -1; ++specialE) {
@@ -311,7 +318,7 @@ void createLangFilename(char *dstFilename, const int gid, const int lang, const
}
}
- static const char *gidExtensions[] = { "", ".K2", ".K3" };
+ static const char *gidExtensions[] = { "", ".K2", ".K3", 0, ".LOL" };
strcat(dstFilename, gidExtensions[gid]);
for (const SpecialExtension *specialE = specialTable; specialE->special != -1; ++specialE) {
@@ -723,11 +730,11 @@ bool extractHofSeqData(PAKFile &out, const Game *g, const byte *data, const uint
controlOffs = 0;
WRITE_BE_UINT16(output, controlOffs);
- if (g->special != k2DemoVersion)
+ if (g->special != k2DemoVersion && g->special != k2DemoLol)
ptr += 4;
output += 2;
- if (g->special != k2DemoVersion) {
+ if (g->special != k2DemoVersion && g->special != k2DemoLol) {
for (int w = 0; w < 2; w++) { //startupCommand, finalCommand
WRITE_BE_UINT16(output, READ_LE_UINT16(ptr));
ptr += 2;
@@ -1063,9 +1070,9 @@ enum {
uint32 getFeatures(const Game *g) {
uint32 features = 0;
- if (g->special == kTalkieVersion || g->special == k2CDFile1E || g->special == k2CDFile1F || g->special == k2CDFile1G || g->special == k2CDFile2E || g->special == k2CDFile2F || g->special == k2CDFile2G || g->game == kKyra3)
+ if (g->special == kTalkieVersion || g->special == k2CDFile1E || g->special == k2CDFile1F || g->special == k2CDFile1G || g->special == k2CDFile1I || g->special == k2CDFile2E || g->special == k2CDFile2F || g->special == k2CDFile2G || g->game == kKyra3)
features |= GF_TALKIE;
- else if (g->special == kDemoVersion || g->special == k2DemoVersion)
+ else if (g->special == kDemoVersion || g->special == k2DemoVersion || g->special == k2DemoLol)
features |= GF_DEMO;
else if (g->special == kFMTownsVersionE || g->special == kFMTownsVersionJ ||
g->special == k2TownsFile1E || g->special == k2TownsFile1J ||
@@ -1344,6 +1351,8 @@ const Game *gameDescs[] = {
kyra3Games,
+ lolDemos,
+
0
};
diff --git a/tools/create_kyradat/create_kyradat.h b/tools/create_kyradat/create_kyradat.h
index c8bcb7d583..8e985f9031 100644
--- a/tools/create_kyradat/create_kyradat.h
+++ b/tools/create_kyradat/create_kyradat.h
@@ -174,6 +174,8 @@ enum kExtractID {
k3ItemMagicTable,
k3ItemStringMap,
+ lSeqplayIntroTracks,
+
kMaxResIDs
};
@@ -202,20 +204,22 @@ enum kSpecial {
k2CDFile2E = 8,
k2CDFile2F = 9,
k2CDFile2G = 10,
-
- k2TownsFile1E = 11,
- k2TownsFile1J = 12,
- k2TownsFile2E = 13,
- k2TownsFile2J = 14,
-
- k2FloppyFile1 = 15,
- k2FloppyFile2 = 16,
-
- k2DemoVersion = 17,
-
- k2DemoVersionTlkE = 18,
- k2DemoVersionTlkF = 19,
- k2DemoVersionTlkG = 20
+ // Italian fan translation
+ k2CDFile1I = 11,
+
+ k2TownsFile1E = 12,
+ k2TownsFile1J = 13,
+ k2TownsFile2E = 14,
+ k2TownsFile2J = 15,
+
+ k2FloppyFile1 = 16,
+ k2FloppyFile2 = 17,
+
+ k2DemoVersion = 18,
+ k2DemoVersionTlkE = 19,
+ k2DemoVersionTlkF = 20,
+ k2DemoVersionTlkG = 21,
+ k2DemoLol = 22
};
struct SpecialExtension {
@@ -225,8 +229,9 @@ struct SpecialExtension {
enum kGame {
kKyra1 = 0,
- kKyra2,
- kKyra3
+ kKyra2 = 1,
+ kKyra3 = 2,
+ kLol = 4
};
struct Game {
diff --git a/tools/create_kyradat/hof_cd.h b/tools/create_kyradat/hof_cd.h
index 1393f74890..431adbb674 100644
--- a/tools/create_kyradat/hof_cd.h
+++ b/tools/create_kyradat/hof_cd.h
@@ -23,6 +23,12 @@ const ExtractEntry kyra2File1CDG[] = {
{ -1, 0, 0 }
};
+const ExtractEntry kyra2File1CDI[] = {
+ { k2SeqplayStrings, 0x0002C566, 0x0002CE7C },
+ { k2SeqplayTlkFiles, 0x0002A2AC, 0x0002A349 },
+ { -1, 0, 0 }
+};
+
const ExtractEntry kyra2File2CDE[] = {
{ k2IngameSfxFiles, 0x0002CB30, 0x0002D221 },
{ k2IngameSfxIndex, 0x000294F0, 0x00029848 },
@@ -47,5 +53,10 @@ const Game kyra2TalkieGames[] = {
{ kKyra2, EN_ANY, k2CDFile2E, "e20d0d2e500f01e399ec588247a7e213", kyra2File2CDE},
{ kKyra2, FR_FRA, k2CDFile2F, "e20d0d2e500f01e399ec588247a7e213", kyra2File2CDF},
{ kKyra2, DE_DEU, k2CDFile2G, "e20d0d2e500f01e399ec588247a7e213", kyra2File2CDG},
+
+ // Italian Fan Translation (using same offsets as English)
+ { kKyra2, IT_ITA, k2CDFile1I, "130795aa8f2333250c895dae9028b9bb", kyra2File1CDI},
+
GAME_DUMMY_ENTRY
};
+
diff --git a/tools/create_kyradat/hof_demo.h b/tools/create_kyradat/hof_demo.h
index f7b15ffa3d..2eaaa3c413 100644
--- a/tools/create_kyradat/hof_demo.h
+++ b/tools/create_kyradat/hof_demo.h
@@ -26,7 +26,8 @@ const Game kyra2Demos[] = {
{ kKyra2, EN_ANY, k2DemoVersion, "a620a37579dd44ab0403482285e3897f", kyra2Demo},
{ kKyra2, EN_ANY, k2CDFile2E, "fa54d8abfe05f9186c05f7de7eaf1480", kyra2DemoCDE},
{ kKyra2, FR_FRA, k2CDFile2F, "fa54d8abfe05f9186c05f7de7eaf1480", kyra2DemoCDF},
- { kKyra2, DE_DEU, k2CDFile2G, "fa54d8abfe05f9186c05f7de7eaf1480", kyra2DemoCDG},
-
+ { kKyra2, DE_DEU, k2CDFile2G, "fa54d8abfe05f9186c05f7de7eaf1480", kyra2DemoCDG},
GAME_DUMMY_ENTRY
};
+
+
diff --git a/tools/create_kyradat/hof_floppy.h b/tools/create_kyradat/hof_floppy.h
index e2709eb3fd..e61f43fb2c 100644
--- a/tools/create_kyradat/hof_floppy.h
+++ b/tools/create_kyradat/hof_floppy.h
@@ -28,6 +28,16 @@ const ExtractEntry kyra2File1G[] = {
{ -1, 0, 0 }
};
+const ExtractEntry kyra2File1I[] = {
+ { k2SeqplayPakFiles, 0x00021189, 0x000211B7 },
+ { k2SeqplayStrings, 0x00022C62, 0x0002352A },
+ { k2SeqplaySfxFiles, 0x0002352A, 0x0002369D },
+ { k2SeqplayIntroTracks, 0x000236AA, 0x000236AA },
+ { k2SeqplayFinaleTracks, 0x000236C7, 0x000236D9 },
+ { k2SeqplaySeqData, 0x00022250, 0x00022944 },
+ { -1, 0, 0 }
+};
+
const ExtractEntry kyra2File2E[] = {
{ k2IngamePakFiles, 0x0035E4E, 0x00362ED },
{ k2IngameSfxFiles, 0x00034700, 0x00034DF1 },
@@ -58,12 +68,24 @@ const ExtractEntry kyra2File2G[] = {
{ -1, 0, 0 }
};
+const ExtractEntry kyra2File2I[] = {
+ { k2IngamePakFiles, 0x00036816, 0x00036CB5 },
+ { k2IngameSfxFiles, 0x000350C6, 0x000357B7 },
+ { k2IngameSfxIndex, 0x0002AB80, 0x0002AED8 },
+ { k2IngameTracks, 0x0003BE78, 0x0003BEF6 },
+ { k2IngameTalkObjIndex, 0x00034872, 0x000348EA },
+ { k2IngameItemAnimData, 0x0003C4E2, 0x0003C82A },
+ { -1, 0, 0 }
+};
+
const Game kyra2FloppyGames[] = {
{ kKyra2, EN_ANY, k2FloppyFile1, "9b0f5e57b5a2ed88b5b989cbb402b6c7", kyra2File1E},
{ kKyra2, FR_FRA, k2FloppyFile1, "df31cc9e37e1cf68df2fdc75ddf2d87b", kyra2File1F},
{ kKyra2, DE_DEU, k2FloppyFile1, "0ca4f9a1438264a4c63c3218e064ed3b", kyra2File1G},
+ { kKyra2, IT_ITA, k2FloppyFile1, "178d3ab913f61bfba21d2fb196405e8c", kyra2File1I},
{ kKyra2, EN_ANY, k2FloppyFile2, "7c3eadbe5122722cf2e5e1611e19dfb9", kyra2File2E},
{ kKyra2, FR_FRA, k2FloppyFile2, "fc2c6782778e6c6d5a553d1cb73c98ad", kyra2File2F},
{ kKyra2, DE_DEU, k2FloppyFile2, "0d9b0eb7b0ad889ec942d74d80dde1bf", kyra2File2G},
+ { kKyra2, IT_ITA, k2FloppyFile2, "3a61ed6b7c00ddae383a0361799e2ba6", kyra2File2I},
GAME_DUMMY_ENTRY
};
diff --git a/tools/create_kyradat/lol_demo.h b/tools/create_kyradat/lol_demo.h
new file mode 100644
index 0000000000..ce114f4e73
--- /dev/null
+++ b/tools/create_kyradat/lol_demo.h
@@ -0,0 +1,15 @@
+const ExtractEntry lolDemo[] = {
+ { k2SeqplayPakFiles, 0x0001AC10, 0x0001AC1C },
+ { k2SeqplayStrings, 0x0001B5EE, 0x0001B6F0 },
+ { k2SeqplaySfxFiles, 0x0001B6F0, 0x0001B7B5 },
+ { k2SeqplaySeqData, 0x0001B320, 0x0001B56C },
+ { lSeqplayIntroTracks, 0x0001B7B5, 0x0001B7CF },
+ { -1, 0, 0 }
+};
+
+const Game lolDemos[] = {
+ { kLol, EN_ANY, k2DemoLol, "30bb5af87d38adb47d3e6ce06b1cb042", lolDemo},
+ GAME_DUMMY_ENTRY
+};
+
+
diff --git a/tools/create_kyradat/misc.h b/tools/create_kyradat/misc.h
index 1e1cd29cc9..f0de5283ad 100644
--- a/tools/create_kyradat/misc.h
+++ b/tools/create_kyradat/misc.h
@@ -363,6 +363,7 @@ const int kyra2CDFile1EngNeed[] = {
k2SeqplayCreditsSpecial,
k2SeqplayStrings,
k2SeqplaySfxFiles,
+ k2SeqplayTlkFiles,
k2SeqplaySeqData,
k2SeqplayIntroTracks,
k2SeqplayFinaleTracks,
@@ -371,11 +372,19 @@ const int kyra2CDFile1EngNeed[] = {
const int kyra2CDFile1FreNeed[] = {
k2SeqplayStrings,
+ k2SeqplayTlkFiles,
-1
};
const int kyra2CDFile1GerNeed[] = {
k2SeqplayStrings,
+ k2SeqplayTlkFiles,
+ -1
+};
+
+const int kyra2CDFile1ItaNeed[] = {
+ k2SeqplayStrings,
+ k2SeqplayTlkFiles,
-1
};
@@ -472,6 +481,15 @@ const int kyra3Need[] = {
-1
};
+const int lolDemoNeed[] = {
+ k2SeqplayPakFiles,
+ k2SeqplayStrings,
+ k2SeqplaySeqData,
+ k2SeqplaySfxFiles,
+ lSeqplayIntroTracks,
+ -1
+};
+
const GameNeed gameNeedTable[] = {
{ kKyra1, -1, kyra1FloppyNeed },
{ kKyra1, kTalkieVersion, kyra1CDNeed },
@@ -485,6 +503,7 @@ const GameNeed gameNeedTable[] = {
{ kKyra2, k2CDFile1E, kyra2CDFile1EngNeed },
{ kKyra2, k2CDFile1F, kyra2CDFile1FreNeed },
{ kKyra2, k2CDFile1G, kyra2CDFile1GerNeed },
+ { kKyra2, k2CDFile1I, kyra2CDFile1ItaNeed }, // Italian fan translation
{ kKyra2, k2CDFile2E, kyra2CDFile2EngNeed },
{ kKyra2, k2CDFile2F, kyra2CDFile2FreNeed },
{ kKyra2, k2CDFile2G, kyra2CDFile2GerNeed },
@@ -496,6 +515,7 @@ const GameNeed gameNeedTable[] = {
{ kKyra2, k2DemoVersionTlkE, kyra2TlkDemoNeed},
{ kKyra2, k2DemoVersionTlkF, kyra2TlkDemoNeed},
{ kKyra2, k2DemoVersionTlkG, kyra2TlkDemoNeed},
+ { kLol, k2DemoLol, lolDemoNeed},
{ kKyra3, -1, kyra3Need },
@@ -512,14 +532,17 @@ const SpecialExtension specialTable[] = {
{ k2CDFile1E, "CD" },
{ k2CDFile1F, "CD" },
{ k2CDFile1G, "CD" },
+ { k2CDFile1I, "CD" },
{ k2CDFile2E, "CD" },
{ k2CDFile2F, "CD" },
{ k2CDFile2G, "CD" },
+
{ k2TownsFile1E, "TNS" },
{ k2TownsFile1J, "TNS" },
{ k2TownsFile2E, "TNS" },
{ k2TownsFile2J, "TNS" },
{ k2DemoVersion, "DEM" },
+ { k2DemoLol, "DEM" },
{ -1, 0 }
};
diff --git a/tools/create_kyradat/pak.h b/tools/create_kyradat/pak.h
index a90b930fcc..1e0fd2c72f 100644
--- a/tools/create_kyradat/pak.h
+++ b/tools/create_kyradat/pak.h
@@ -35,7 +35,7 @@ public:
bool saveFile(const char *file);
void clearFile() { delete _fileList; _fileList = 0; }
- const uint32 getFileSize() const { return _fileList->getTableSize()+5+4+_fileList->getFileSize(); }
+ uint32 getFileSize() const { return _fileList->getTableSize()+5+4+_fileList->getFileSize(); }
void drawFileList();
diff --git a/tools/credits.pl b/tools/credits.pl
index 7df218e4c0..2c5fed46f6 100755
--- a/tools/credits.pl
+++ b/tools/credits.pl
@@ -463,6 +463,12 @@ begin_credits("Credits");
end_persons();
end_section();
+ begin_section("Retired Project Leaders");
+ begin_persons();
+ add_person("Vincent Hamm", "yaz0r", "ScummVM co-founder, Original Cruise/CinE author");
+ add_person("Ludvig Strigeus", "ludde", "Original ScummVM and SimonVM author");
+ end_persons();
+ end_section();
begin_section("Engine Teams");
begin_section("SCUMM");
@@ -618,7 +624,6 @@ begin_credits("Credits");
end_section();
begin_section("PlayStation 2");
- add_person("Robert G&ouml;ffringmann", "lavosspawn", "");
add_person("Max Lingua", "sunmax", "");
end_section();
@@ -654,9 +659,10 @@ begin_credits("Credits");
end_section();
begin_section("Miscellaneous");
- add_person("David Corrales-Lopez", "david_corrales", "Filesystem access improvements");
+ add_person("David Corrales-Lopez", "david_corrales", "Filesystem access improvements (GSoC 2007 task)");
add_person("Jerome Fisher", "KingGuppy", "MT-32 emulator");
add_person("Jochen Hoenicke", "hoenicke", "Speaker &amp; PCjr sound support, Adlib work");
+ add_person("Chris Page", "cp88", "Return to launcher, savestate improvements, leak fixes, ... (GSoC 2008 task)");
add_person("Robin Watts", "robinwatts", "ARM assembly routines for nice speedups on several ports; improvements to the sound mixer");
end_section();
end_section();
@@ -678,13 +684,14 @@ begin_credits("Credits");
add_person("Nicolas Bacca", "arisme", "Former WinCE porter");
add_person("Ralph Brorsen", "painelf", "Help with GUI implementation");
add_person("Jamieson Christian", "jamieson630", "iMUSE, MIDI, all things musical");
+ add_person("Hans-J&ouml;rg Frieden", "", "Former AmigaOS 4 packager");
+ add_person("Robert G&ouml;ffringmann", "lavosspawn", "Original PS2 porter");
add_person("R&uuml;diger Hanke", "", "Port: MorphOS");
- add_person("Vincent Hamm", "yaz0r", "ScummVM co-founder, Original Cruise/CinE author");
add_person("Felix Jakschitsch", "yot", "Zak256 reverse engineering");
add_person("Mutwin Kraus", "mutle", "Original MacOS porter");
add_person("Peter Moraliyski", "ph0x", "Port: GP32");
+ add_person("Juha Niemim&auml;ki", "", "Formaer AmigaOS 4 packager");
add_person("Jeremy Newman", "laxdragon", "Former webmaster");
- add_person("Ludvig Strigeus", "ludde", "Original ScummVM and SimonVM author");
add_person("Lionel Ulmer", "bbrox", "Port: X11");
add_person("Won Star", "wonst719", "Former GP32 porter");
end_persons();
@@ -696,9 +703,7 @@ begin_credits("Credits");
begin_section("Packages");
begin_section("AmigaOS 4");
- add_person("Hans-J&ouml;rg Frieden", "", "");
add_person("Hubert Maier", "Raziel_AOne", "");
- add_person("Juha Niemim&auml;ki", "", "");
end_section();
begin_section("Atari/FreeMiNT");
@@ -773,6 +778,7 @@ begin_credits("Credits");
add_person("Stuart Caie", "", "Decoders for Simon 1 Amiga data files");
add_person("Paolo Costabel", "", "PSP port contributions");
add_person("Thierry Crozat", "criezy", "Support for Broken Sword 1 Macintosh version");
+ add_person("Martin Doucha", "next_ghost", "CinE engine objectification");
add_person("Thomas Fach-Pedersen", "madmoose", "ProTracker module player");
add_person("Benjamin Haisch", "john_doe", "Heavily improved de-/encoder for DXA videos");
add_person("Janne Huttunen", "", "V3 actor mask support, Dig/FT SMUSH audio");
@@ -807,14 +813,17 @@ begin_credits("Credits");
add_person("Sander Buskens", "", "For his work on the initial reversing of Monkey2");
add_person("", "Canadacow", "For the original MT-32 emulator");
add_person("Kevin Carnes", "", "For Scumm16, the basis of ScummVM's older gfx codecs");
+ add_person("Curt Coder", "", "For the original TrollVM (preAGI) code");
add_person("Patrick Combet", "Dorian Gray", "For the original Gobliiins ADL player");
add_person("Ivan Dubrov", "", "For contributing the initial version of the Gobliiins engine");
+ add_person("Till Kresslein", "Krest", "For design of modern ScummVM GUI");
add_person("", "Jezar", "For his freeverb filter implementation");
add_person("Jim Leiterman", "", "Various info on his FM-TOWNS/Marty SCUMM ports");
add_person("", "lloyd", "For deep tech details about C64 Zak &amp; MM");
add_person("Sarien Team", "", "Original AGI engine code");
add_person("Jimmi Th&oslash;gersen", "", "For ScummRev, and much obscure code/documentation");
add_person("", "Tristan", "For additional work on the original MT-32 emulator");
+ add_person("James Woodcock", "", "Soundtrack enhancements");
end_persons();
add_paragraph(
diff --git a/tools/md5table.c b/tools/md5table.c
index 3f85ac338b..c8f7eb9e09 100644
--- a/tools/md5table.c
+++ b/tools/md5table.c
@@ -85,6 +85,7 @@ static const StringMap platformMap[] = {
{ "PC-Engine", "kPlatformPCEngine" },
{ "SEGA", "kPlatformSegaCD" },
{ "Windows", "kPlatformWindows" },
+ { "Wii", "kPlatformWii" },
{ "All?", "kPlatformUnknown" },
{ "All", "kPlatformUnknown" },
diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt
index 4da978914d..1196ef9cc8 100644
--- a/tools/scumm-md5.txt
+++ b/tools/scumm-md5.txt
@@ -402,6 +402,7 @@ brstorm Bear Stormin'
thinker1 Big Thinkers First Grade
5c21fc49aee8f46e58fef21579e614a1 -1 us All - - - Kirben
+ 632d2fddb8ba97723fa15334763ae857 33270 en Windows - - - George Kormendi
0f5935bd5e88ba6f09e558d64459746d 30919 us Windows - Demo - khalek
@@ -436,8 +437,11 @@ readtime Blue's Reading Time Activities
95818b178d473c989ac753574e8892aa -1 en All - Demo - Kirben
fbear Fatty Bear's Birthday Surprise
+ 13d2a86a7290813a1c386490447d72db -1 en 3DO HE 61 - - George Kormendi
5b08000a9c47b2887df6506ac767ca68 -1 en 3DO HE 61 - - sev
+ 6bca7a1a96d16e52b8f3c42b50dbdca3 -1 jp 3DO HE 61 - - George Kormendi
3824e60cdf639d22f6df92a03dc4b131 7732 en DOS HE 61 - - khalek
+ 4f1d6f8b38343dba405472538b5037ed 7717 en DOS HE 61 - - George Kormendi
ef74d9071d4e564b037cb44bd6774de7 -1 hb DOS HE 61 - - sev
3df6ead57930488bc61e6e41901d0e97 -1 en Mac HE 61 - - khalek
179879b6e35c1ead0d93aab26db0951b 13381 en Windows HE 70 - - khalek
@@ -465,6 +469,7 @@ freddi Freddi Fish 1: The Case of the Missing Kelp Seeds
e44ea295a3f8fe4f41983080dab1e9ce -1 fr Mac HE 90 Updated - ThierryFR
746e88c172a5b7a1ae89ac0ee3ee681a -1 ru Windows HE 90 Updated - sev
a197a87ae77f3b3333f09a7a2c448fe2 -1 en Windows HE 99 Updated - Jonathan
+ 57a5cfec9ef231a007043cc1917e8988 -1 en Wii HE 100 - - sanguinehearts
084ed0fa98a6d1e9368d67fe9cfbd417 -1 en Windows HE 71 Demo - khalek
c8aac5e3e701874e2fa4117896f9e1b1 -1 en Mac HE 73 Demo - khalek, sev
@@ -516,6 +521,7 @@ freddi4 Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch
7c2e76087027eeee9c8f8985f93a1cc5 13584 en All - Demo - khalek
c25755b08a8d0d47695e05f1e2111bfc -1 us All - Demo - sev
+ fa84cb1018103a4ee4e5fa8041c1d0d1 13609 de Windows - Demo - George Kormendi
ebd324dcf06a4c49e1ba5c231eee1060 -1 us All HE 99 Demo - sev
688328c5bdc4c8ec4145688dfa077bf2 -1 de All HE 99 Demo - Joachim Eberhard
03d3b18ee3fd68114e2a687c871e38d5 -1 us Windows HE 99 Mini Game - eriktorbjorn
@@ -553,6 +559,7 @@ FreddisFunShop Freddi Fish's One-Stop Fun Shop
catalog Humongous Interactive Catalog
11e6e244078ff09b0f3832e35420e0a7 -1 en Windows - Demo - khalek, sev
037385a953789190298494d92b89b3d0 -1 en Windows HE 72 Demo - khalek, sev
+ 74da3494fbe1a7d20213b0afe0954755 10841544 fr All HE CUP Preview - George Kormendi
4c4820518e16e1a0e3616a3b021a04f3 10927456 de All HE CUP Preview - Kirben
airport Let's Explore the Airport with Buzzy
@@ -566,7 +573,9 @@ airport Let's Explore the Airport with Buzzy
farm Let's Explore the Farm with Buzzy
fbbbb38a81fc9d6a61d509278390a290 -1 en Mac - - - khalek
+ a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi
a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben
+ a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi
39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard
bf8b52fdd9a69c67f34e8e9fec72661c -1 en Windows HE 71 Demo - khalek, sev
@@ -586,10 +595,12 @@ pajama Pajama Sam 1: No Need to Hide When It's Dark Outside
37aed3f91c1ef959e0bd265f9b13781f -1 us All HE 100 Updated - Kirben
782393c5934ecd0b536eaf5fd541bd26 -1 en Windows HE 100 Updated - Jonathan
4aa93cb30e485b728504ba3a693f12bf -1 ru Windows HE 100 - - sev
+ c225bec1b6c0798a2b8c89ac226dc793 -1 en Wii HE 100 - - sanguinehearts
f237bf8a5ef9af78b2a6a4f3901da341 18354 en All - Demo - khalek, sev
7f945525abcd48015adf1632637a44a1 -1 fr All - Demo - Kirben
0305e850382b812fec6e5998ef88a966 -1 nl Windows - Demo - adutchguy
+ 87df3e0074624040407764b7c5e710b9 18354 nl Windows - Demo - George Kormendi
d7ab7cd6105546016e6a0d46fb36b964 -1 en All HE 100 Demo - khalek
pajama2 Pajama Sam 2: Thunder and Lightning Aren't so Frightening
@@ -621,6 +632,7 @@ pajama3 Pajama Sam 3: You Are What You Eat From Your Head to Your Feet
4fe6a2e8df3c4536b278fdd2fbcb181e -1 en Windows - Mini Game - Trekky
679855cf61932f9bf995c8f3677380ed -1 fr Windows - Demo - Mevi
c8c5baadcbfc8d0372ed4335abace8a7 -1 fr Windows - Demo - Mevi
+ 784b499c98d07260a30952685758636b 13911 de Windows - Demo - George Kormendi
3e48298920fab9b7aec5a971e1bd1fab -1 gb Windows - Demo - eriktorbjorn
cf90b4db5486ef798db78fe6fbf897e5 -1 us Windows - Demo - khalek
@@ -648,6 +660,7 @@ puttrace Putt-Putt Enters the Race
981e1e1891f2be7e25a01f50ae55a5af -1 us All HE 98 - - Kirben
1ed22f601f8b3695804a6583cc3083f1 -1 nl All HE 98.5 - - daniel9
33e989f85da700e2014d00f345cab3d7 -1 fr Windows HE 98.5 - - gist974
+ 5719fc8a13b4638b78d9d8d12f091f94 -1 fr Windows HE 98.5 - - thyphoon
b47be81e39a9710f6f595f7b527b60f8 -1 gb Windows HE 99 - - Reckless
055ffe4f47753e47594ac67823220c54 -1 de All HE 99 - - Joachim Eberhard
62050da376483d8edcbd98cd26b6cb57 -1 ru Windows HE 99 - - sev
@@ -658,12 +671,14 @@ puttrace Putt-Putt Enters the Race
aaa587701cde7e74692c68c1024b85eb -1 nl All HE 99 Demo - joostp
0bf1a3eb198ca1bd2ebe104825cec770 -1 fr Windows HE 99 Demo - Mevi
c8575e0b973ff1723aba6cd92c642db2 -1 fr Windows HE 99 Demo - Mevi
+ 3769b56c9a22f5521d74525ee459f88d 13108 de Windows HE 99 Demo - George Kormendi
7c8100e360e8ef05f88069d4cfa0afd1 13108 gb Windows HE 99 Demo - eriktorbjorn
6b27dbcd8d5697d5c918eeca0f68ef6a 3901484 All All HE CUP Preview - sev
puttmoon Putt-Putt Goes to the Moon
a9543ef0d79bcb47cd76ec197ad0a967 -1 en 3DO - - - sev
780e4a0ae2ff17dc296f4a79543b44f8 -1 All DOS - - - khalek
+ b9bb68c5d2c9b6e2d9c513a29a754a57 7828 en DOS - - - George Kormendi
697c9b7c55a05d8199c48b48e379d2c8 -1 hb DOS - - - sev
9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek
9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek
@@ -685,9 +700,11 @@ puttcircus Putt-Putt Joins the Circus
3af61c5edf8e15b43dbafd285b2e9777 -1 hb Windows - Demo - Ori Avtalion
puttputt Putt-Putt Joins the Parade
+ 7766c9487f9d53a8cb0edabda5119c3d 8022 en DOS HE 60 - - George Kormendi
0b3222aaa7efcf283eb621e0cefd26cc -1 ru DOS HE 60 - - sev
7e151c17adf624f1966c8fc5827c95e9 -1 en 3DO HE 61 - - khalek
be2abe172f58db170de3a037daa1dd27 -1 jp 3DO HE 61 - - clone2727
+ ee41f6afbc5b26fa475754b56fe92048 8032 jp 3DO HE 61 - - George Kormendi
9708cf716ed8bcc9ff3fcfc69413b746 -1 en DOS HE 61 - - khalek
e361a7058ed8e8ebb462663c0a3ae8d6 -1 hb DOS HE 61 - - sev
684732efb5799c0f78804c99d8de9aba -1 en Mac HE 61 - - khalek
@@ -703,6 +720,7 @@ puttzoo Putt-Putt Saves the Zoo
1005456bfe351c1b679e1ff2dc2849e9 -1 All Windows - - - khalek
c3b22fa4654bb580b20325ebf4174841 -1 nl Windows - - - joostp
9781422e4288dbc090720e4563168ba7 -1 fr Windows - - - gist974
+ 0f9d3317910ac7a9f449243118884ada 42070 de Windows - - - George Kormendi
92e7727e67f5cd979d8a1070e4eb8cb3 -1 en All HE 98.5 Updated - cyx
3a3e592b074f595489f7f11e150c398d -1 us Windows HE 99 Updated - Adrian
@@ -734,13 +752,16 @@ PuttTime Putt-Putt Travels Through Time
balloon Putt-Putt and Pep's Balloon-O-Rama
08cc5c3eedaf72ebe12734eee94f7fa2 -1 en All HE 80 - - Kirben
+ bab0fb81dcb12b8930c5d850b8f2a7de 12800 de Windows HE 80 - - George Kormendi
145bd3373574feb668cc2eea2ec6cf86 -1 ru Windows HE 80 - - sev
2232b0b9411575b1f9961713ebc9de61 -1 es Windows HE 80 - - exiltd
d7b247c26bf1f01f8f7daf142be84de3 -1 en Windows HE 99 Updated - iziku
8e3241ddd6c8dadf64305e8740d45e13 -1 en All HE 100 Updated - Kirben
dog Putt-Putt and Pep's Dog on a Stick
+ bd5fd7835335dfce03064d5f77b7f0ae 19681 nl Windows - - - George Kormendi
eae95b2b3546d8ba86ae1d397c383253 -1 en All - - - Kirben
+ 839a658f7d22de00787ebc945348cdb6 19681 de Windows - - - George Kormendi
d4b8ee426b1afd3e53bc0cf020418cf6 -1 en Windows HE 99 - - sev
activity Putt-Putt & Fatty Bear's Activity Pack
@@ -769,6 +790,7 @@ spyfox SPY Fox 1: Dry Cereal
72ac6bc980d5101c2142189d746bd62f -1 ru Windows HE 99 - - sev
3de99ef0523f8ca7958faa3afccd035a -1 us All HE 100 Updated - Kirben
23394c8d29cc63c61313959431a12476 -1 en Windows HE 100 Updated - Jonathan
+ 50b831f11b8c4b83784cf81f4dcc69ea -1 en Wii HE 100 - - sanguinehearts
53e94115b55dd51d4b8ff0871aa1df1e 20103 en All - Demo - khalek, sev
fbdd947d21e8f5bac6d6f7a316af1c5a 15693 en All - Demo - sev
@@ -789,6 +811,8 @@ spyfox2 SPY Fox 2: Some Assembly Required
7222f260253f325c21fcfa68b5bfab67 -1 us All - Demo - Kirben
732845548b1d6c2da572cb6a1bf81b07 -1 de All - Demo - Joachim Eberhard
e62056ba675ad65d8854ab3c5ad4b3c0 -1 en Windows - Mini Game - Trekky
+ 22de86b2f7ec6e5db745ed1123310b44 15832 fr Windows - Demo - George Kormendi
+ 204453e33456c4faa26e276229fe5b76 14689 de Windows - Demo - George Kormendi
19bf6938a94698296bcb0c99c31c91a7 -1 gb Windows - Demo - eriktorbjorn
49a1739981a89066b1121fac04b710f4 5756234 All All HE CUP Preview - sev